Ë
    tPêj£k ã            r       ó$#  — U d Z ddlZddlZddlZddlZddl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 ddlmZmZmZ ddlmZmZmZmZmZmZmZmZ ddlZddlZddlmZmZmZm Z m!Z!m"Z"m#Z# ddl$Z$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/ ddl0m1Z1 ddl2m3Z3 ddl4m5Z5 ddl6m7Z7m8Z8m9Z9 ddl:m;Z; ddl<­ ddl<m=Z=m>Z>m?Z? ddl@mAZAmBZBmCZCmDZDmEZE ddlFmGZGmHZHmIZI ddlJmKZK ddlLmMZM ddlNmOZO ddlPmQZQmRZR ddlSmTZTmUZU ddlVmWZW ddlXmYZY ddlZm[Z[ ddl\m]Z] ddl^m_Z_ ddl`maZambZbmcZcmdZdmeZemfZfmgZgmhZh ddlimjZj dd lkmlZlmmZmmnZn dd!lompZp dd"lqmrZrmsZsmtZtmuZumvZvmwZw dd#lxmyZy dd$lzm{Z{ dd%l|m}Z} dd&l~mZ dd'l€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‹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— dd0l˜m™Z™ dd1lšm›Z› dd2lœm�Z� dd3lžmŸZŸ dd4l m¡Z¡ dd5l¢m£Z£m¤Z¤m¥Z¥m¦Z¦m§Z§ dd6l¨m©Z© dd7lªm«Z«m¬Z¬m­Z­ erdd8l®m¯Z¯ dd9l®m°Z±  ed:e²¬;«      Z³ G d<„ d=e«      Z´ G d>„ d?e«      Zµ G d@„ dAe«      Z¶dBe‡e³   dCe’e³   fdD„Z·dEe�dCdFfdG„Z¸dEe�dCdHfdI„Z¹dEe�dCe’e´   fdJ„ZºdEe�dCe’e5   fdK„Z»dEe�dCe¶fdL„Z¼dMe½dz  dCdfdN„Z¾dOe¿e>z  fdP„ZÀdQeÁdRe½dz  dCeÂdz  fdS„ZÃdTe½dCefdU„ZÄ	 �d’dOeÅdVeÆdTe½dz  dWe½dz  dCdf
dX„ZÇdYeÈdRe½dz  dZe½dz  dCeÆfd[„ZÉd\e½dz  dQeÁdYeÈd]e­d^eÊf
d_„ZËdOe¿d`eÌe½   dz  fda„ZÍdQeÁdYeÈdOe¿d^eÊfdb„ZÎdYeÈdce¬dz  fdd„ZÏdeeÐdz  dCeÑdz  fdf„ZÒdYeÈdOe¿fdg„ZÓdQeÁdz  dYeÈdOe¿d^eÊdCeÆf
dh„ZÔdiee½eÕf   dz  dCdfdj„ZÖ	 �d’dYeÈdOe¿e×z  dke�dz  dleÆdRe½dz  dCedm   fdn„ZØ e«       ZÙeeÚdo<   dOe¿dpeÅdCeÅfdq„ZÛ eÜdrdsh«      ZÝeeÚdt<   dOe²dz  due>dYeÈdCdfdv„ZÞdwdwdxœdyeÌdz  dYeÈdzeÆd{eÆdCdf
d|„ZßdOeàdYeÈdCdfd}„Zád~eÌeâ   dz  deãdz  dYeÈd€eÆdQeÁdz  dCdfd�„ZädZe½dz  dEe�dz  fd‚„Zå eÜg dƒ¢«      Zæ	 �d“dOe¿e×z  d„eÆdCdfd…„ZçdOe¿dYeÈd†e½dz  dQeÁdz  dCeèf
d‡„Zédˆee>   dOe¿e×z  d‰eêdz  dŠeêdz  d‹eÅe½eêf   dŒeÅe½eêf   d�e½dCdfdŽ„Zëdˆee>   dOe¿e×z  d‰eêdz  dŠeêdz  d�e½dCdfd�„Zìdˆee>   dQeÁdOe¿e×z  dCdfd�„Zídˆee>   dQeÁdOe¿e×z  dCdfd‘„ZîdQeÁdOe¿e×z  dEe�dCdfd’„Zï eÜeð�jâ                  �jä                  eð�jæ                  �jä                  h«      ZôeeÚd“<   d”e½dOe¿e×z  dEe�d•e[dCdf
d–„Zõdˆee>   d—eödOe¿e×z  dCdfd˜„Z÷dˆee>   d—eödOe¿e×z  dCdfd™„ZødYeÈdše½dEe�dCdfd›„Zùd—eödOe¿e×z  dEe�dCdfdœ„ZúeÙ�j÷                  d�džg eeK«      geè¬Ÿ«      e{ eeK«       edd ¬¡«      fdOe¿dYeÈd†e½dz  fd¢„«       «       ZüeÙ�j÷                  d£džg eeK«      g¬¤«      e{ eeK«       edd ¬¡«      fdOe¿dYeÈd†e½dz  fd¥„«       «       ZýdOe²d¦eÅd§eÅdCeÅfd¨„ZþdOe×eÿz  due>fd©„�Z dpeÅdue>dCeÅfdª„�ZdOe×due>dCeÆfd«„�Zd¬eãdz  dCdfd­„�Z	 �d’d®e½dz  dEe�dz  d¯e½dz  dCe>fd°„�ZdOe×due>dCe½fd±„�Z	 	 �d”d²e×dYeÈd†e½dz  dEe�dz  d•e[d³e‚dke�dz  d´edz  due>dz  dCeÅe½eÕf   fdµ„�ZdOd¶d·ed¸   due>dEe�dz  d•e[d¹eÆdCeÑdz  fdº„�ZdOe×due>dYeÈdke�dz  dleÆdEed•e[dCdfd»„�ZeÙ�j÷                  d¼džg eeK«      g¬¤«      e{ eeK«       edd ¬¡«      fd½e"dOe×dYeÈd†e½dz  fd¾„«       «       �Z	eÙ�j÷                  d¿džg eeK«      ge¤¬Ÿ«      e{ eeK«       edd ¬¡«      fdOe£dYeÈd†e½dz  fdÀ„«       «       �Z
d®e½dÁ�edue>dz  dCe¦fdÂ„�ZeÙ�j÷                  dÃdžg eeK«      ge¤¬Ÿ«      e{ eeK«       edd ¬¡«      fdOe¥dYeÈd†e½dz  fdÄ„«       «       �ZdÅe>dÆ�edÇeÈdke�fdÈ„�ZeÙ�j÷                  dÉdžg eeK«      g¬¤«      e{ eeK«       edd ¬¡«      fdO�edYeÈd†e½dz  fdÊ„«       «       �ZdËe½dÌee½ee½eÕf   f   d•e*dz  dCeÅe½eÅe½eÕf   f   fdÍ„�ZeÙ�j÷                  dÎdžg eeK«      gdw¬Ï«      d eeK«      fdO�edz  dYeÈfdÐ„«       �ZeÙ�j)                  dÑdžg eeK«      g¬¤«      e{ ejB                  ddÒ¬Ó«       eeK«      fdÅe½dz  dYeÈfdÔ„«       «       �ZdÕeÌe½   dz  dke�dz  dleÆdCedm   fdÖ„�Zdg i i d×ddddddddddddddddi dddØddg i i dddddddddddddddddddddddddf7dÙedÚ   dÛe½dz  dÕeÌdÜeÅdÝeÅdÞeãdßeãdz  dàe½dz  dáeãdz  dâeãdz  d¬eãdz  dãeÆdz  däe½dz  d®e½dz  dÅe½dz  dRe½dz  dåe½dz  dZe½dz  dæe½dz  dçe½dz  dèe½dz  déeêdz  dieÅdz  dêeêdz  dëeêdz  dìedí   dîeÅdz  d¯e½dz  dïeÌdz  dðeÅdz  dÌeÅdz  dñeÅdz  dòeÅdz  dóeÅdz  dôeÅdz  dõeÅdz  döeÌdz  d÷eÌdz  døeÌdz  dùeÌdz  dše½dz  d”e½dz  dúedû   dz  düeÆdz  dýe½dz  dþe½dz  dyeÌdz  dÿe½dz  �d e½dz  �de½dz  deeÐdz  dVeÆdz  dTe½dz  �deÅdz  �deÌe½   dz  d~eÌdz  fp�d„�ZdYeÈ�de>dEe�d•e[f�d„�Z�de>d•e[dYeÈdEe�dCeÆf
�d„�Z	 �d’�deÌd•e[dYeÈd†e½dz  dC�eeÅdz  eÌe>   f   f
�d	„�Z	 �d’dˆee>   dYeÈd†e½dz  dCeÌeÅe½eÕf      f�d
„�Z	 �d’�deee½eÕf      dEe��d�ddCdf�d„�Z	 	 �d”dˆee>   dEe�dYeÈd†e½dz  �d�ddCdf�d„�Z	 �d’�deÌe½   d•e[dEe�dYeÈd†e½dz  dC�eeÅdz  eÌe>   f   f�d„�ZdEe�dYeÈ�de½�de½dCdf
�d„�Z dYeÈdCdf�d„�Z!eÙ�j÷                  �d�dg eeK«      g¬¤«       eeK«       e!dw�d¬¡«      fdYeÈ�deÆf�d„«       �Z"eÙ�j)                  �d�dg eeK«      g¬¤«       eeK«      fdYeÈf�d„«       �Z#dOeÿdz  dCe½f�d„�Z$dE�d�de½�d e½�d!e½dz  dCdf
�d"„�Z%dEe��d#e>�d$e½dÅe½dOeÿdz  dYeÈd†e½dz  d•e[d³e‚dCeèf�d%„�Z&eÙ�j÷                  �d&džg eeK«      g¬¤«      eÙ�j÷                  �d'džg eeK«      g¬¤«      e{dd eeK«       edd ¬¡«      fdÅe½dz  dOeÿdz  dYeÈd†e½dz  dCeèdz  f
�d(„«       «       «       �Z'�d#e>dYeÈdEe�d•e[dCdf
�d)„�Z(�d*eÕ�d#e>dCeãf�d+„�Z)�d,e½�d-eãdCdf�d.„�Z*d~eeÕ   e½z  dz  dC�eee½eÕf   �d/f   f�d0„�Z+�d1ee½eÕf   dCee½eÕf   f�d2„�Z,dEe��d$e½d~eeÕ   e½z  dz  dCdf�d3„�Z-eÙ�j÷                  �d4džg eeK«      g¬¤«      e{ eeK«       edd ¬¡«      fdÅe½dO�e.dYeÈd†e½dz  dCeÅe½ef   f
�d5„«       «       �Z/dYeÈdRe½dz  dZe½dz  dše½dz  d¯e½dz  �d6e½dz  dEe�dC�e0dz  f�d7„�Z1�d8�e0dz  dEe�dCeÌ�e   f�d9„�Z2dYeÈ�d:eÌ�e   dCeÌe½   f�d;„�Z3dYeÈ�d:eÌ�e   dCeÌe½   f�d<„�Z4dYeÈ�d:eÌ�e   dCeÌe½   f�d=„�Z5�d8�e0dz  dYeÈdEe�dCeÌe½   f�d>„�Z6�d8�e0dz  dYeÈdEe�dCeÌe½   f�d?„�Z7 eÜ�d@�dAh«      �Z8eeÚ�dB<   eÙ�j)                  �dCdžg eeK«      g¬¤«      e{ eeK«       e!�dD�dE�dD�¬F«       e!�dG�dH�dD�dI�¬J«       e!d�dK¬¡«       e!d�dL¬¡«       e!d�dM¬¡«       e!d�dN¬¡«       e!d�dO¬¡«       e!dw�dP¬¡«       e!dw�dQ¬¡«       e!dw�dR¬¡«       e!d�dS¬Ó«       e!�dT�dU¬Ó«       e!d�dV¬¡«       e!d�dW¬¡«       e!d�dX¬¡«       e!d�dY¬¡«       e!d�dZ¬¡«       e!dw�d[¬¡«       e!d�d\¬¡«      fd½e"dYeÈ�d]eê�d^eêdRe½dz  dZe½dz  dše½dz  �d6e½dz  d¯e½dz  �d_eÆ�d`eÆ�daeÆ�dbe½dz  �dce½�ddeÌe½   dz  �dee½dz  d”e½dz  �dfe½dz  dæe½dz  �dgeÆ�dhe½dz  dC�e9f,�di„«       «       �Z:dYeÈdEe��djeÌeÕ   �dkeÌe½   dCdf
�dl„�Z;eÙ�j)                  �dmdžg eeK«      g¬¤«      e{ eeK«       e!�dD�dD�dE�¬n«       e!�do�dD�dI�dH�¬p«       e!d�dq¬¡«       e!d�dr¬¡«      fdYeÈ�d]eê�d^eê�dse½dz  dZe½dz  dCeÅe½ef   f�dt„«       «       �Z<�dbe½dz  �dce½dCeÅe½e½f   dz  f�du„�Z=�dve½�dwedCeÅe½eÕf   f�dx„�Z>	 	 	 	 	 	 	 �d•dRe½dz  dZe½dz  dše½dz  d¯e½dz  �d6e½dz  �dye½dz  �dzeÌe½   dz  �d{eÌe½   dz  �daeÆd”e½dz  �dfe½dz  dæe½dz  �d|eÆ�dve½dz  dCee½eÕf   f�d}„�Z?	 	 	 	 	 	 	 	 	 	 	 	 	 	 �d–dEe��d]eê�d^eêdRe½dz  dZe½dz  dše½dz  d¯e½dz  �d6e½dz  �dye½dz  �d_eÆ�dzeÌe½   dz  �d{eÌe½   dz  �daeÆ�dbe½dz  �dce½�ddeÌe½   dz  �dee½dz  d”e½dz  �dfe½dz  dæe½dz  �d|eÆ�dve½dz  dC�e9f.�d~„�Z@dCee½eÕf   f�d„�ZAdYeÈ�d€e½dz  dEe�dz  d•e[d^e½dCdf�d�„�ZBeÙ�j÷                  �d‚džg eeK«      g¬¤«      e{ eeK«       edd ¬¡«      fdO�eC�dƒe"dYeÈd†e½dz  dCe>dz  f
�d„„«       «       �ZDeÙ�j÷                  �d…džg eeK«      g¬¤«      e{ eeK«       edd ¬¡«      fdO�eC�dƒe"dYeÈd†e½dz  f�d†„«       «       �ZEeÙ�j÷                  �d‡džg eeK«      g�eF¬Ÿ«      e{ eeK«      fd½e"dYeÈf�dˆ„«       «       �ZGdYeÈdÅe½dz  �de>dCeÆf�d‰„�ZHdYeÈd½e"�dŠeee½e½f      dC�eIf�d‹„�ZJ e�j–                  �dŒ«      �ZLeeÚ�d�<   d¯e½dz  dCdf�dŽ„�ZM	 �d’d¯e½dz  dEe�dz  �d�e½dz  dCdf�d�„�ZNdÌeÅdz  dCdf�d‘„�ZOy(—  z`
KEY MANAGEMENT

All /key management endpoints

/key/generate
/key/info
/key/update
/key/delete
é    N)Ú	AwaitableÚCallableÚMappingÚSequence)ÚdatetimeÚ	timedeltaÚtimezone)ÚTYPE_CHECKINGÚAnyÚFinalÚLiteralÚOptionalÚProtocolÚTypeVarÚcast)Ú	APIRouterÚDependsÚHeaderÚHTTPExceptionÚQueryÚRequestÚstatus)Úverbose_proxy_logger)Úuuid)Ú	DualCache)ÚLENGTH_OF_LITELLM_GENERATED_KEYÚLITELLM_PROXY_ADMIN_NAMEÚMINIMUM_CUSTOM_KEY_LENGTHÚUI_SESSION_TOKEN_TEAM_ID)Úduration_in_seconds)Ú
safe_dumps)ÚCredentialItem)Ú(rotate_mcp_server_credentials_master_keyÚ&rotate_mcp_user_credentials_master_keyÚ#rotate_mcp_user_env_vars_master_key)Ú)rotate_sso_identity_assertions_master_key)Ú*)ÚLitellm_EntityTypeÚLiteLLM_VerificationTokenÚ
hash_token)Ú_delete_cache_key_objectÚcan_team_access_modelÚget_org_objectÚget_project_objectÚget_team_object)Úabbreviate_api_keyÚ0enforce_batch_enqueued_token_limit_is_admin_onlyÚ-enforce_output_token_estimates_are_admin_only)Úuser_api_key_auth)Úpublish_auth_cache_invalidation)Úlogging_metadata_config_error)Údecrypt_callback_varsÚencrypt_callback_vars)Úcoordination_redis_cacheÚpublish_config_change)Ú!check_org_admin_can_generate_keys©Úget_budget_reset_time)ÚUserApiKeyCache)ÚKeyManagementEventHooks)Úbuild_model_max_budget_usage)Ú+_check_passthrough_routes_caller_permissionÚ_is_user_org_admin_for_teamÚ_is_user_team_adminÚ_set_object_metadata_fieldÚ_team_member_has_permissionÚ_user_has_admin_viewÚvalidate_budget_durationÚvalidate_finite_spend)Ú_add_model_to_db)Ú sync_key_access_group_membershipÚ-sync_key_regeneration_access_group_membershipÚ'sync_key_update_access_group_membership)Úwith_settings_updated_at)Ú_set_object_permissionÚ attach_object_permission_to_dictÚ&handle_update_object_permission_commonÚ%validate_key_mcp_servers_against_teamÚ&validate_key_search_tools_against_teamÚ'validate_key_vector_stores_against_team)ÚTeamMemberPermissionChecks)Úmanagement_endpoint_wrapper)Ú_is_master_key)Úget_ui_settings_cached)ÚPrismaClientÚProxyLoggingÚ_hash_token_if_neededÚhandle_exception_on_proxyÚis_valid_api_key)ÚBaseRepository)ÚBudgetRepository)ÚConfigParamÚConfigRepository)ÚCredentialsRepository)ÚModelRepository)ÚTableActions)Ú"DeletedVerificationTokenRepositoryÚ%DeprecatedVerificationTokenRepository)ÚTeamRepository)ÚUserRepository)ÚVerificationTokenRepository)ÚRouter)Úraise_if_unsafe_secret_name)Ú
get_secret)ÚBulkUpdateKeyRequestÚBulkUpdateKeyResponseÚBulkUpdateTeamKeysRequestÚFailedKeyUpdateÚSuccessfulKeyUpdate)Ú
Deployment)ÚBudgetConfigÚPersonalUIKeyGenerationConfigÚTeamUIKeyGenerationConfig)ÚPrisma)ÚmodelsÚ_RepositoryModelT)Úboundc                   ó�   — e Zd ZdZededz  fd„«       Zededz  fd„«       Zededz  fd„«       Zde	ee
f   fd„Zde	ee
f   fd„Zy)	Ú_UserRowLikezCRead-only view of the user columns ``/key/list`` expands keys with.ÚreturnNc                  ó   — y ©N© ©Úselfs    ú€/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/management_endpoints/key_management_endpoints.pyÚuser_idz_UserRowLike.user_id¦   s   € Ø%(ó    c                  ó   — y r|   r}   r~   s    r€   Ú
user_emailz_UserRowLike.user_email©   ó   € Ø(+r‚   c                  ó   — y r|   r}   r~   s    r€   Ú
user_aliasz_UserRowLike.user_alias¬   r…   r‚   c                  ó   — y r|   r}   r~   s    r€   Ú
model_dumpz_UserRowLike.model_dump¯   ó   � r‚   c                  ó   — y r|   r}   r~   s    r€   Údictz_UserRowLike.dict±   rŠ   r‚   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚpropertyÚstrr�   r„   r‡   r   Úobjectr‰   rŒ   r}   r‚   r€   ry   ry   £   sl   „ ÙMàØ(˜˜t™Ò(ó Ø(àØ+˜C $™JÒ+ó Ø+àØ+˜C $™JÒ+ó Ø+à5˜G C¨ KÑ0Ó5à/�g˜c 6˜kÑ*Ô/r‚   ry   c                   ó   — e Zd ZU ee   ed<   y)Ú	_TxTablesÚlitellm_proxymodeltableN)r�   rŽ   r�   rb   r“   Ú__annotations__r}   r‚   r€   r•   r•   ´   s   … Ø)¨&Ñ1Ô1r‚   r•   c                   óP   — e Zd Z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
y)Ú_ConfigTableActionszYConfig table surface this module needs; the shared repository seam exposes no ``update``.rz   c              ƒ   ó   K  — y ­wr|   r}   r~   s    r€   Ú	find_manyz_ConfigTableActions.find_many»   s   è ø� ùó   ‚ÚwhereÚdataNc             ƒ   ó   K  — y ­wr|   r}   )r   r�   rž   s      r€   Úupdatez_ConfigTableActions.update½   s   è ø€ ð
 !ùrœ   )r�   rŽ   r�   r�   r   r^   r›   r   r’   r“   r    r}   r‚   r€   r™   r™   ¸   sL   „ Ùcà; ¨+Ñ!6Ó;ð!ð �s˜F�{Ñ#ð!ð �c˜6�kÑ"ð	!ð
 
�tÑ	ô!r‚   r™   Ú
repositoryrz   c                 ó.   — t        d| j                  «      S )NzTableActions[_RepositoryModelT])r   Útable)r¡   s    r€   Ú_prisma_tabler¤   Å   s   € ô Ø)¨:×+;Ñ+;óð r‚   Úprisma_clientz<TableActions[prisma_models.LiteLLM_DeletedVerificationToken]c                 ó,   — t        | «      j                  S r|   )rc   r£   ©r¥   s    r€   Ú!_deleted_verification_token_tabler¨   Í   s   € ô .¨mÓ<×BÑBÐBr‚   z?TableActions[prisma_models.LiteLLM_DeprecatedVerificationToken]c                 ó,   — t        | «      j                  S r|   )rd   r£   r§   s    r€   Ú$_deprecated_verification_token_tablerª   Ó   s   € ô 1°Ó?×EÑEÐEr‚   c                 ó,   — t        | «      j                  S r|   )rf   r£   r§   s    r€   Ú_user_tabler¬   Ù   s   € Ü˜-Ó(×.Ñ.Ð.r‚   c                 ó@   — t        dt        | «      j                  «      S )NzTableActions[CredentialItem])r   r`   r£   r§   s    r€   Ú_credentials_tabler®   Ý   s    € ÜØ&Ô(=¸mÓ(L×(RÑ(Róð r‚   c                 ó@   — t        dt        | «      j                  «      S )Nr™   )r   r_   r£   r§   s    r€   Ú_config_tabler°   ã   s    € ÜØÔ/°Ó>×DÑDóð r‚   Úcustom_key_valuec              ƒ   óª   K  — | €yt        «       ƒ d{  –—† }|j                  dd«      du r$t        j                  d«       t	        dddi¬	«      ‚y7 Œ=­w)
zHRaise 403 if custom API keys are disabled and a custom key was provided.NÚdisable_custom_api_keysFTz;Custom API key rejected: disable_custom_api_keys is enabledé“  ÚerrorzVCustom API key values are disabled by your administrator. Keys must be auto-generated.©Ústatus_codeÚdetail)rV   Úgetr   Úwarningr   )r±   Úui_settingss     r€   Ú_check_custom_key_allowedr¼   é   sa   è ø€ àÐØä5Ó7×7€KØ‡�Ð0°%Ó8¸DÑ@Ü×$Ñ$Ð%bÔcÜØØÐuÐvô
ð 	
ð Að 8ús   ‚A“A”>Arž   c                 ó   — | j                   d uS r|   ©Úteam_id©rž   s    r€   Ú_is_team_keyrÁ   ÷   s   € Ø�<‰<˜tÐ#Ð#r‚   Ú
team_tabler�   c                 ól   — |€y | j                   D ]"  }|j                  €Œ|j                  |k(  sŒ |c S  y r|   )Úmembers_with_rolesr�   )rÂ   r�   Úmembers      r€   Ú_get_user_in_teamrÆ   û   s>   € Ø€ØØ×/Ñ/ò ˆØ�>‰>Ñ%¨&¯.©.¸GÓ*CØŠMðð r‚   Úrotation_intervalc                 ó|   — t        j                  t        j                  «      }t	        | «      }|t        |¬«      z   S )a  
    Helper function to calculate the next rotation time for a key based on the rotation interval.

    Args:
        rotation_interval: String representing the rotation interval (e.g., '30d', '90d', '1h')

    Returns:
        datetime: The calculated next rotation time in UTC
    ©Úseconds)r   Únowr	   Úutcr    r   )rÇ   rË   Úinterval_secondss      r€   Ú_calculate_key_rotation_timerÎ     s3   € ô —‘œhŸl™lÓ+€CÜ1Ð2CÓDÐØ”Ð#3Ô4Ñ4Ð4r‚   Úauto_rotateÚexisting_key_aliasc                 ó  — |r~|r{t         j                  �Lt         j                  j                  du r0| j                  d«      €|€t	        dt
        j                  dd¬«      ‚| j                  ||t        |«      dœ«       yyy)ax  
    Helper function to set rotation fields in key data if auto_rotate is enabled.

    Args:
        data: Dictionary to update with rotation fields
        auto_rotate: Whether auto rotation is enabled
        rotation_interval: The rotation interval string (required if auto_rotate is True)
        existing_key_alias: The existing key alias from the database (if any)
    NTÚ	key_aliasz�key_alias is required when auto_rotate=True and store_virtual_keys is enabled. This ensures stable secret naming during rotation.é�  ©ÚmessageÚtypeÚparamÚcode)rÏ   rÇ   Úkey_rotation_at)	ÚlitellmÚ_key_management_settingsÚstore_virtual_keysr¹   ÚProxyExceptionÚProxyErrorTypesÚbad_request_errorr    rÎ   )rž   rÏ   rÇ   rÐ   s       r€   Ú_set_key_rotation_fieldsrà     sŠ   € ñ Ñ(ä×,Ñ,Ð8Ü×0Ñ0×CÑCÀtÑKØ—‘˜Ó%Ð-Ø"Ð*ä ð \Ü$×6Ñ6Ø!Øô	ð ð 	�‰à*Ø%6Ü#?Ð@QÓ#Rñõ	
ð )€{r‚   Úuser_api_key_dictr¿   c                 ó   — | j                   �(| j                   t        j                  j                  k(  ry|�&|| j                  k(  sJ d|› d| j                  › �«       ‚|� | j
                  �| j
                  t        k(  ryy)z‚
    Assert user only creates/updates keys for themselves

    Relevant issue: https://github.com/BerriAI/litellm/issues/7336
    Tz6User can only create keys for themselves. Got user_id=z
, Your ID=)Ú	user_roleÚLitellmUserRolesÚPROXY_ADMINÚvaluer�   r¿   Ú
UI_TEAM_ID©rá   r�   r¿   s      r€   Ú_is_allowed_to_make_key_requestré   9  s‘   € ð ×"Ñ"Ð.Ð3D×3NÑ3NÔRb×RnÑRn×RtÑRtÒ3tØàÐØÐ+×3Ñ3Ò3ð 	
ØDÀWÀIÈZÐXi×XqÑXqÐWrÐsó	
Ð3ð ÐØ×$Ñ$Ð0Ð5F×5NÑ5NÔR\Ò5\Øàr‚   Úassigned_user_idÚteam_key_generationÚroutec                 óî  — | �,t        || ¬«      }|€t        dd| › d|j                  › �¬«      ‚t        ||j                  ¬«      }|j                  d uxr' |j                  t
        j                  j                  k(  }|ry|€'t        dd|j                  › d|j                  › �¬«      ‚d|v r1|j                  |d   vr t        dd|j                  › d	|d   › �¬«      ‚t        j                  |||¬
«       y)N©rÂ   r�   rÓ   úUser=z not assigned to team=r¶   TÚallowed_team_member_roleszTeam member role z" not in allowed_team_member_roles=©Úteam_member_objectrÂ   rì   )rÆ   r   r¿   r�   rã   rä   rå   ræ   ÚrolerS   Ú.does_team_member_have_permissions_for_endpoint)rê   rÂ   rá   rë   rì   Úkey_assigned_user_in_teamrò   Úis_admins           r€   Ú%_team_key_operation_team_member_checkr÷   S  sM  € ð Ð#Ü+<È
Ð\lÔ+mÐ!à$Ð,ÜØØÐ/Ð0Ð0FÀz×GYÑGYÐFZÐ[ôð ô
 !2¸ZÐQb×QjÑQjÔ kÐð 	×#Ñ#¨4Ð/ÒuÐ4E×4OÑ4OÔSc×SoÑSo×SuÑSuÑ4uð ñ ØØ	Ð	#ÜØØÐ,×4Ñ4Ð5Ð5KÈJ×L^ÑL^ÐK_Ð`ô
ð 	
ð
 	$Ð':Ñ:Ø×#Ñ#Ð+>Ð?ZÑ+[Ñ[äØØ&Ð'9×'>Ñ'>Ð&?Ð?aÐbuð  wRñ  cSð  bTð  Uô
ð 	
ô
 ×MÑMØ-ØØõð
 r‚   Úrequired_paramsc                 óf   — |€y| j                  d¬«      }|D ]  }||vsŒt        dd|› d�¬«      ‚ y)NT©Úexclude_unsetrÓ   zRequired param z not in datar¶   )r‰   r   )rž   rø   Ú	data_dictr×   s       r€   Ú$_key_generation_required_param_checkrý   �  sS   € ØÐØà—‘°T�Ó:€IØ ò ˆØ˜	Ò!ÜØØ(¨¨¨|Ð<ôð ðð r‚   c                 óŠ  — |j                   t        j                  j                  k(  ryt        j
                  �&dt        j
                  v rt        j
                  d   }nt        ddg¬«      }t        |j                  | |||¬«       t        ||j                  d«      «       t        j                  || |j                  ¬«       y)	NTrë   ÚadminÚuser©rð   ©rê   rÂ   rá   rë   rì   rø   ©rá   rÂ   Úaccess_group_ids)rã   rä   rå   ræ   rÚ   Úkey_generation_settingsrs   r÷   r�   rý   r¹   rS   Ú'enforce_member_can_assign_access_groupsr  )rÂ   rá   rž   rì   Ú_team_key_generations        r€   Ú_team_key_generation_checkr  �  s¿   € ð ×"Ñ"Ô&6×&BÑ&B×&HÑ&HÒHØÜ×&Ñ&Ð2Ð7LÔPW×PoÑPoÑ7oÜ&×>Ñ>Ð?TÑUÑä8Ø'.°Ð&7ô 
Ðô *ØŸ™ØØ+Ø0Øõô )ØØ× Ñ Ð!2Ó3ôô ×FÑFØ+ØØ×.Ñ.õð r‚   Úpersonal_key_generationc                 ót   — |�d|vry| j                   |d   vr t        dd|d   › d| j                   › �¬«      ‚y)NÚallowed_user_rolesTrÓ   zBPersonal key creation has been restricted by admin. Allowed roles=z. Your role=r¶   )rã   r   )rá   r	  s     r€   Ú_personal_key_membership_checkr  µ  s„   € ð Ð&Ð*>ÐF]Ñ*]Øà×"Ñ"Ð*AÐBVÑ*WÑWÜØØWÐXoð  qEñ  YFð  XGð  GSð  Te÷  Toñ  Toð  Spð  qô
ð 	
ð
 r‚   Úobject_permissionc                 óH   — | €y t        t        | j                  d¬«      «      S )NTrú   )r   ÚObjectPermissionDictr‰   )r  s    r€   Ú_object_permission_to_dictr  Å  s+   € ð Ð ØÜÔ$Ð&7×&BÑ&BÐQUÐ&BÓ&VÓWÐWr‚   c                 ó  — t        j                  | d |j                  ¬«       t        j                  �t        j                  j                  d«      €yt        j                  d   }t        | |¬«       t        ||j                  d«      «       y)Nr  r	  T)r	  rø   )rS   r  r  rÚ   r  r¹   r  rý   )rá   rž   Ú_personal_key_generations      r€   Ú_personal_key_generation_checkr  Í  s‰   € Ü×FÑFØ+ØØ×.Ñ.õô 	×'Ñ'Ð/Ü×*Ñ*×.Ñ.Ð/HÓIÐQàä&-×&EÑ&EÐF_Ñ&`Ðä"ØØ 8õô
 )ØØ ×$Ñ$Ð%6Ó7ôð
 r‚   c                 óZ  — t        |¬«      }|j                  duxr' |j                  t        j                  j                  k(  }|rZ| €*t
        j                  �t        dd|j                  › �¬«      ‚| €|ryt        dd|j                  › �¬«      ‚t        | |||¬«      S t        ||¬«      S )	z^
    Check if admin has restricted key creation to certain roles for teams or individuals
    rÀ   NrÓ   z1Unable to find team object in database. Team ID: r¶   T©rÂ   rá   rž   rì   )rá   rž   )rÁ   rã   rä   rå   ræ   rÚ   r  r   r¿   r  r  )rÂ   rá   rž   rì   Úis_team_keyÚ	_is_admins         r€   Úkey_generation_checkr  é  sË   € ô &¨4Ô0€Kà×#Ñ#¨4Ð/ÒuÐ4E×4OÑ4OÔSc×SoÑSo×SuÑSuÑ4uð ñ ØÐ¤'×"AÑ"AÐ"MÜØØJÈ4Ï<É<È.ÐYôð ð ÐÙØäØØJÈ4Ï<É<È.ÐYôð ô *Ø!Ø/ØØô	
ð 	
ô .Ð@QÐX\Ô]Ð]r‚   Úmetadatac                 ó<   — t        | «      }|�t        dd|i¬«      ‚y)zãKey-level logging writes go through key metadata, not /team/callback.

    Without this the same New Relic config the team endpoint rejects would be
    accepted here and then silently ignored or misrouted at request time.
    NrÓ   rµ   r¶   )r5   r   )r  rµ   s     r€   Ú#raise_on_invalid_key_logging_configr    s+   € ô 1°Ó:€EØÐÜ¨°W¸eÐ4DÔEÐEð r‚   Ú
llm_routerÚpremium_userTc                 ó  — 	 t        | |xs |j                  |j                  ¬«       t        |j                  ||¬«       y# t        $ r}t	        dt        |«      ¬«      ‚d}~wt        $ r}t	        dt        |«      ¬«      ‚d}~ww xY w)zF
    Check if user is allowed to make a key request, for this key
    rè   r´   r¶   Néô  )ru   r  r  T)	ré   r�   r¿   ÚAssertionErrorr   r’   Ú	ExceptionÚ_check_model_access_groupru   )rá   rž   r  r  r�   Úes         r€   Úcommon_key_access_checksr$    sŒ   € ð
Ü'Ø/ØÒ+˜tŸ|™|Ø—L‘Lõ	
ô  Ø�{‰{ØØ!õð
 øô! ò 
ÜØÜ�q“6ô
ð 	
ûô ò 
ÜØÜ�q“6ô
ð 	
ûð
ús#   ‚&A Á	BÁ
A Á BÁ,BÂBÚrouterÚ	data_jsonc                 ó  — | j                   }|€|j                  dd«       |S |j                  |d<   |t        j                  k(  rdg|d<   |S |t        j
                  k(  rdg|d<   |S |t        j                  k(  rdg|d<   |S )z
    Handle the key type.
    NÚkey_typeÚllm_api_routesÚallowed_routesÚmanagement_routesÚinfo_routes)r(  Úpopræ   ÚLiteLLMKeyTypeÚLLM_APIÚ
MANAGEMENTÚ	READ_ONLY)rž   r&  r(  s      r€   Úhandle_key_typer2  A  s¢   € ð —m‘m€HØÐØ�‰�j $Ô'ØÐØ$ŸN™N€IˆjÑØ”>×)Ñ)Ò)Ø'7Ð&8ˆ	Ð"Ñ#ð
 Ðð	 
”^×.Ñ.Ò	.Ø':Ð&;ˆ	Ð"Ñ#ð Ðð 
”^×-Ñ-Ò	-Ø'4 oˆ	Ð"Ñ#ØÐr‚   r)  r,  Ú&_NON_ADMIN_SAFE_ALLOWED_ROUTES_PRESETSÚexisting_key_rowc                 ó"  — |j                   t        j                  j                  k(  ry| €yt	        | dd«      xs
 t        «       }d|vryt	        | dd«      }|�|dk(  rt        dd¬«      ‚t	        |dd«      }||k7  rt        dd|› d	|› �¬«      ‚y)
u  
    Non-admin callers must not rebind a key's ``user_id`` to a different
    user. The ``user_id`` on a verification token is what
    ``_return_user_api_key_auth_obj`` resolves against ``litellm_usertable``
    to derive the request's role; a non-admin rebinding their own key's
    ``user_id`` to a ``PROXY_ADMIN`` row promotes themselves.

    ``/key/update`` already enforces this inline; ``/key/regenerate`` did
    not. Sharing the check keeps both endpoints â€” and any future
    regenerate-style endpoint â€” consistent.
    NÚmodel_fields_setr�   Ú r´   z5Non-admin users cannot remove the user_id from a key.r¶   z<Non-admin caller is not allowed to rebind the key from user=z	 to user=)rã   rä   rå   ræ   ÚgetattrÚsetr   )rž   r4  rá   Ú
fields_setÚincoming_user_idÚexisting_user_ids         r€   Ú)_validate_caller_can_change_key_ownershipr=  V  sÆ   € ð  ×"Ñ"Ô&6×&BÑ&B×&HÑ&HÒHØØ€|Øô   Ð&8¸$Ó?ÒHÄ3Ã5€JØ˜
Ñ"ØÜ% d¨I°tÓ<ÐØÐÐ#3°rÒ#9ÜØØJô
ð 	
ô &Ð&6¸	À4ÓHÐØÐ+Ò+ÜØðØ(Ð)¨Ð3CÐ2DðFô
ð 	
ð ,r‚   F)Úallowed_routes_was_providedÚallow_safe_presetsr*  r>  r?  c                ó¨   — |s| sy|j                   t        j                  j                  k(  ry|r| rt	        d„ | D «       «      ryt        dddi¬«      ‚)aÀ  
    Require PROXY_ADMIN when `allowed_routes` is present in the request body,
    unless the caller went through the `key_type` preset flow.

    Raw-body call sites pass
    `allowed_routes_was_provided="allowed_routes" in data.model_fields_set` so a
    caller that omits the field (model default flows through) is distinct from
    one that sends any explicit value.

    Post-`handle_key_type` call sites pass `allow_safe_presets=True` with the
    values derived by `handle_key_type`; those values are not from the request
    body, so `allowed_routes_was_provided` stays False and the safe-preset
    carve-out below accepts any list of tokens in
    `_NON_ADMIN_SAFE_ALLOWED_ROUTES_PRESETS`.
    Nc              3   ó,   K  — | ]  }|t         v –— Œ y ­wr|   )r3  )Ú.0Úrs     r€   ú	<genexpr>z:_check_allowed_routes_caller_permission.<locals>.<genexpr>¡  s   è ø€ ÒTÀ�Ô;Ô;ÑTùs   ‚r´   rµ   zjOnly proxy admins can set `allowed_routes` on a key. Use `key_type` to pick a preset route bucket instead.r¶   )rã   rä   rå   ræ   Úallr   )r*  rá   r>  r?  s       r€   Ú'_check_allowed_routes_caller_permissionrF  „  s_   € ñ, '©~ØØ×"Ñ"Ô&6×&BÑ&B×&HÑ&HÒHØáÙÜÑTÀ^ÔTÔTàÜ
ØàðHð
ôð r‚   c                 óª   — d| j                   v }|s| j                  sy|j                  t        j                  j
                  k(  ryt        dddi¬«      ‚)zû
    Require PROXY_ADMIN when `permissions` is present in the request body.

    Presence is detected via `data.model_fields_set` so a caller that
    omits the field (default flows through) is distinct from one that
    sends any explicit value.
    ÚpermissionsNr´   rµ   z(Only proxy admins can set `permissions`.r¶   )r6  rH  rã   rä   rå   ræ   r   )rž   rá   Úpermissions_in_requests      r€   Ú$_check_permissions_caller_permissionrJ  ¯  sZ   € ð %2°T×5JÑ5JÐ$JÐÙ!¨$×*:Ò*:ØØ×"Ñ"Ô&6×&BÑ&B×&HÑ&HÒHØÜ
ØØÐCÐDôð r‚   Úbudget_limitsÚdelegation_ceilingÚis_ui_session_team_keyc           	      ót  ‡— | syt        d„ | D «       d«      }|�t        ddd|j                  › d�i¬«      ‚|j                  t        j
                  j                  k(  ry|ry|j                  r|€t        dddi¬«      ‚‰€yt        ˆfd	„| D «       d«      }|� t        ddd|j                  › d
‰› d�i¬«      ‚y)aº  
    Enforce three invariants on `budget_limits`:

    - Every `budget_limits[*].max_budget` must be a finite number; applies
      to every caller including proxy admin.
    - A CLI session token caller may not set `budget_limits` on a personal
      key (one with no `team_id`); mirrors the scalar `max_budget` guard in
      `_common_key_generation_helper`.
    - Non-admin callers may not set a window above their delegation ceiling.
    Nc              3   ó`   K  — | ]&  }t        j                  |j                  «      rŒ#|–— Œ( y ­wr|   )ÚmathÚisfiniteÚ
max_budget©rB  Úws     r€   rD  z:_check_budget_limits_delegation_ceiling.<locals>.<genexpr>Ø  s   è ø€ ÒZ A¼d¿m¹mÈAÏLÉLÕ>YœaÑZùs   ‚$.§.rÓ   rµ   z budget_limits entry max_budget (z) must be a finite number.r¶   zVbudget_limits cannot be set without specifying team_id when using a CLI session token.c              3   óB   •K  — | ]  }|j                   ‰kD  sŒ|–— Œ y ­wr|   ©rR  )rB  rT  rL  s     €r€   rD  z:_check_budget_limits_delegation_ceiling.<locals>.<genexpr>ë  s   øè ø€ Ò^ a¸A¿L¹LÐK]Ó<]¤Ñ^ùs   ƒ˜ú-) cannot exceed the caller's own max_budget (ú).)Únextr   rR  rã   rä   rå   ræ   Úis_session_token)rK  rL  rá   rM  rÂ   Ú
non_finiteÚover_ceilings    `     r€   Ú'_check_budget_limits_delegation_ceilingr]  Å  s  ø€ ñ" ØÜÑZ¨ÔZÐ\`Óa€JØÐÜØØÐ @À×AVÑAVÐ@WÐWqÐrÐtô
ð 	
ð ×"Ñ"Ô&6×&BÑ&B×&HÑ&HÒHØÙØØ×)Ò)¨jÐ.@ÜØàÐrðô
ð 	
ð Ð!ØÜÓ^¨=Ô^Ð`dÓe€LØÐÜØàØ6°|×7NÑ7NÐ6Oð PBØBTÐAUÐUWðYðô
ð 	
ð  r‚   c              ƒ   óÆ   K  — | €t        dd¬«      ‚|€t        dd¬«      ‚t        t        |«      «      j                  d| i¬«      ƒ d{  –—† }|€t        dd¬«      ‚y	7 Œ­w)
z[
    Validate team_id is used in the request body for generating a service account key
    NrÓ   ú[team_id is required for service account keys. Please specify `team_id` in the request body.r¶   zgprisma_client is required for service account keys. Please specify `prisma_client` in the request body.r¿   ©r�   z]team_id does not exist in the database. Please specify a valid `team_id` in the request body.T)r   r¤   re   Úfind_unique)r¿   r¥   Úteams      r€   Ú0validate_team_id_used_in_service_account_requestrc  ø  sŽ   è ø€ ð €ÜØØpô
ð 	
ð
 ÐÜØØ|ô
ð 	
ô &¤n°]Ó&CÓD×PÑPØ˜'Ð"ð Qó ÷ €Dð €|ÜØØrô
ð 	
ð ðús   ‚AA!Á
AÁA!)rR  Úsoft_budgetÚmax_parallel_requestsÚ	tpm_limitÚ	rpm_limitÚfill_defaultsc           
      óø  — | D ]<  }|\  }}|t         v sŒ|€Œt        j                  |«      rŒ*t        dd|› d|› �i¬«      ‚ t        j
                  €y| D ]£  }|\  }}t        t        j
                  |d«      }|€Œ&|€|sŒ+t        | ||«       Œ9|dv r||kD  sŒCt        dd|› d|› d|› �i¬«      ‚|d	v sŒ_t        |¬
«      }|dk(  rt        d«      }nt        |¬
«      }||kD  sŒŽt        dd|› d|› d|› �i¬«      ‚ y)zå
    Enforce upperbound limits on key parameters.

    For key generation (fill_defaults=True): fills None values with upperbound defaults.
    For key update (fill_defaults=False): only validates explicitly provided values.
    NrÓ   rµ   z$ must be a finite number. Received: r¶   )rR  re  rf  rg  z. is over max limit set in config - user_value=z; max_value=)Úbudget_durationÚduration©rk  ú-1Úinf)
Ú_BUDGET_NUMERIC_KEYSrP  rQ  r   rÚ   Úupperbound_key_generate_paramsr8  Úsetattrr    Úfloat)rž   rh  ÚelemÚkeyræ   Úupperbound_valueÚupperbound_durationÚuser_durations           r€   Ú_enforce_upperbound_key_paramsrx    s€  € ð ò ˆØ‰
ˆˆUØÔ&Ò&¨5Ñ+<Ü—=‘= Õ'Ü#Ø #Ø#¨ uÐ,PÐQVÐPWÐ%XÐYôð ð	ô ×-Ñ-Ð5Øàò !ˆØ‰
ˆˆUÜ"¤7×#IÑ#IÈ3ÐPTÓUÐØÑ'Øˆ}Ú Ü˜D #Ð'7Õ8àð ñ ð Ð/Ó/Ü+Ø(+à '¨C¨5Ð0^Ð_dÐ^eÐeqð  sCð  rDð  *Eð$ôð ð Ð;Ò;Ü*=ÐGWÔ*XÐ'Ø ’}Ü(-¨e«™ä(;ÀUÔ(K˜Ø$Ð':Ó:Ü+Ø(+à '¨C¨5Ð0^Ð_dÐ^eÐeqð  sCð  rDð  *Eð$ôð ñ9!r‚   Úlitellm_changed_byc           	   ƒ   óæ  K  — ddl m}m}m}m} t        || ||¬«       t        | j                  «       t        | j                  «       | j                  du r6|j                  t        j                  j                  k7  rt        dddi¬«      ‚t!        | d |d	¬
«       t#        | d |d	¬
«       | j                  �F| j                  j%                  d«      �+| j&                  €t)        | j&                  |¬«      ƒ d {  –—†  | j*                  }| j&                  }	t,        j.                  �Â| D ]½  }
|
\  }}|€G|dk7  s|| j0                  vr4|dv r0t,        j.                  j%                  |«      }|€ŒCt3        | ||«       ŒQ|dk(  r1|g k(  r,t3        | |t,        j.                  j%                  |g «      «       Œ‡|dk(  sŒ�|i k(  sŒ“t3        | |t,        j.                  j%                  |i «      «       Œ¿ t5        | d¬«       |j&                  t6        k(  xr |	d u}|j8                  r@|j                  t        j                  j                  k7  r|s|�|€t        ddd|› d�i¬«      ‚|j*                  �|j*                  n|j8                  r|�|j*                  nd }|j                  t        j                  j                  k7  r!|s|�|�||kD  rt        ddd|› d|› d�i¬«      ‚t;        | j<                  ||||¬«       t?        | |¬«       	 ddl m!}  || |«      } | jJ                  }|�¯| jL                  �£tO        | jL                  | jP                  xs i ¬«      }|jS                  |jU                  d¬«      «      }tW        |«      jX                  j[                  i |¥|j\                  xs ||j\                  xs |dœ¥¬«      ƒ d {  –—† }t_        |dd «      }t`        D ]4  }t_        | |d «      €Œtc        | |t_        | |«      ¬ «       te        | |«       Œ6 tf        D ]4  }t_        | |d «      €Œtc        | |t_        | |«      ¬ «       te        | |«       Œ6 | ji                  dd¬!«      }tk        | |«      }tm        |j%                  d"«      |d¬#«       d$|v r|jo                  d$d «      |d%<   |�||d<   d|v r|jo                  dd «      |d&<   |j\                  �|j\                  |d'<   |j\                  |d(<   d)|v rodd*l m} |dur+|d)   �&tq        d+tr        jt                  j                  › �«      ‚|j%                  d«      }|sd)|d)   i|d<   n|d)   |d   d)<   |jo                  d)«       |j                  t        j                  j                  k(  }tw        |j%                  d,«      |||¬-«      ƒ d {  –—† }|�||d,<   ty        |j%                  d,«      ||¬.«      ƒ d {  –—†  t{        |j%                  d,«      ||¬.«      ƒ d {  –—†  t,        j.                  �t,        j.                  j%                  d,«      nd }t}        |t~        «      r\|j%                  d,«      }|€t        |«      |d,<   n:t}        |t~        «      r*|j�                  «       D ]  \  }}|jƒ                  ||«       Œ t…        ||¬/«      ƒ d {  –—† }t‡        |j%                  d0d «      ¬1«       t‰        |j%                  d0d «      |¬2«      ƒ d {  –—†  t‹        | jŒ                  «      ƒ d {  –—†  | jŒ                  �h| jŒ                  j�                  d3«      sMt‘        | jŒ                  «      d4kD  r!| jŒ                  d d5 › d6| jŒ                  d7d  › �nd6}t        ddd8|› �i¬«      ‚| jŒ                  �3t‘        | jŒ                  «      t’        k  rt        ddd9t’        › d:�i¬«      ‚| j”                  �ædd;l m}mK}  |rÜ|j                  d uxr' |j                  t        j                  j                  k(  }!|d uxr) |j”                  d uxr | j”                  |j”                  k(  }"|!s"|"s t™        || j”                  |¬<«      ƒ d {  –—†  t›        | j”                  | |¬=«      ƒ d {  –—† }#|#€t        dd>| j”                  › �¬«      ‚t�        |#| |¬?«      ƒ d {  –—†  tŸ        dDd@d	i|¤dAd	i¤Žƒ d {  –—† }$| jL                  |$dB<   t         j£                  |$«      }$|$j¤                  |$_S        t©        jª                  t­        j®                  | |$||¬C«      «       |$S 7 �Œ,# tD        $ r!}tG        jH                  d|«       Y d }~�Œ@d }~ww xY w7 �Œ�7 �Œº7 �Œ‘7 �Œo7 �ŒÀ7 �Œ‚7 �Œh7 �Œ7 Œú7 ŒÊ7 Œ³­w)ENr   )Úlitellm_proxy_admin_namer  r  r¥   )rá   rž   r  r  Tr´   rµ   úBOnly proxy admins can enable throttle_on_budget_exceeded on a key.r¶   rt  ©rž   Úexisting_metadatará   ÚentityÚservice_account_id©r¿   r¥   rj  )rR  r�   r¿   re  rf  rg  rj  rk  ru   r  ©rh  rÓ   zmax_budget (zJ) cannot be set without specifying team_id when using a CLI session token.rW  rX  )rK  rL  rá   rM  rÂ   ©rž   rá   )Ú&apply_enterprise_key_management_paramsz_litellm.proxy.proxy_server.generate_key_fn(): Enterprise key management params not applied - %s)rd  Úmodel_max_budget©Úexclude_none)Ú
created_byÚ
updated_byrÀ   Ú	budget_id©Úobject_dataÚ
field_nameræ   ©rû   r‡  r*  ©r*  rá   r?  rR  Úkey_max_budgetÚkey_budget_durationrˆ  r‰  Útags)r  z)Only premium users can add tags to keys. r  ©r  Úteam_objr¥   Úis_proxy_admin©r  r”  r•  )r&  r¥   rÒ   ©rÒ   )rÒ   r¥   úsk-é   é   z****éüÿÿÿzIInvalid key format. LiteLLM Virtual Key must start with 'sk-'. Received: z9Invalid key format. LiteLLM Virtual Key must be at least ú characters long.©r¥   Úuser_api_key_cache©rá   Úorganization_idr¥   ©Úorg_idrž  r¥   ú+Organization not found for organization_id=©Ú	org_tablerž   r¥   Úrequest_typeÚ
table_namerd  )rž   Úresponserá   ry  r}   )XÚlitellm.proxy.proxy_serverr{  r  r  r¥   r$  rF   rj  r  r  Úthrottle_on_budget_exceededrã   rä   rå   ræ   r   r2   r1   r¹   r¿   rc  rR  rÚ   Údefault_key_generate_paramsr6  rq  rx  r   rZ  r]  rK  rJ  ÚFlitellm_enterprise.proxy.management_endpoints.key_management_endpointsr„  r!  r   ÚdebugrŠ  rd  ÚLiteLLM_BudgetTabler…  Újsonify_objectÚjsonr]   r£   Úcreater�   r8  Ú1LiteLLM_ManagementEndpoint_MetadataFields_PremiumrC   ÚdelattrÚ)LiteLLM_ManagementEndpoint_MetadataFieldsr‰   r2  rF  r-  Ú
ValueErrorÚCommonProxyErrorsÚnot_premium_userrP   rQ   rR   Ú
isinstancerŒ   ÚitemsÚ
setdefaultrM   Ú_validate_key_alias_formatÚ_enforce_unique_key_aliasr¼   rt  Ú
startswithÚlenr   r   rž  Ú#_validate_caller_can_assign_key_orgr-   Ú_check_org_key_limitsÚgenerate_key_helper_fnÚGenerateKeyResponseÚmodel_validateÚtoken_idÚtokenÚasyncioÚcreate_taskr>   Úasync_key_generated_hook)%rž   rá   ry  rÂ   r{  r  r  r¥   Ú_requested_max_budgetÚ_requested_team_idrs  rt  ræ   Údefault_valuerM  rL  r„  r#  Ú
_budget_idÚ
budget_rowÚ
new_budgetÚ_budgetÚfieldr&  Ú	_metadataÚ_is_proxy_admin_callerÚnormalized_object_permissionÚ_default_object_permissionÚ_caller_object_permissionÚ	_op_fieldÚ_op_default_valueÚ_maskedrž  Ú_is_proxy_adminÚ_org_inherited_from_teamr¥  r¨  s%                                        r€   Ú_common_key_generation_helperrÛ  X  sN
  è ø€ ÷ó ô Ø+ØØØ!õ	ô ˜T×1Ñ1Ô2Ü'¨¯©Ô6à×'Ñ'¨4Ñ/Ð4E×4OÑ4OÔSc×SoÑSo×SuÑSuÒ4uÜØØÐaÐbô
ð 	
ô
 2ØØØ+Øõ	ô 5ØØØ+Øõ	ð ‡}�}Ð  T§]¡]×%6Ñ%6Ð7KÓ%LÐ%XÐ]a×]iÑ]iÐ]qÜ>Ø—L‘LØ'ô
÷ 	
ð 	
ð $(§?¡?ÐØ $§¡Ðô ×*Ñ*Ð6Øò 	UˆDØ‰JˆC�à�ØÐ-Ò-°¸D×<QÑ<QÑ1QØð	ñ
ô !(× CÑ C× GÑ GÈÓ L�Ø Ñ,Ü˜D # }Õ5Ø˜’ U¨b¢[Ü˜˜c¤7×#FÑ#F×#JÑ#JÈ3ÐPRÓ#SÕTØ˜
Ó" u°£{Ü˜˜c¤7×#FÑ#F×#JÑ#JÈ3ÐPRÓ#SÕTð/	Uô4 # 4°tÕ<ð /×6Ñ6Ô:RÑRÒuÐWiÐquÐWuÐð 	×*Ò*Ø×'Ñ'Ô+;×+GÑ+G×+MÑ+MÒMÙ&Ø!Ð-ØÐäØàØ"Ð#8Ð"9ð :Ið Iðô
ð 	
ð ×'Ñ'Ð3ð 	×$Ò$à'8×'IÒ'IÈjÐNdˆj×#Ò#Ðjnð ð 	×#Ñ#Ô'7×'CÑ'C×'IÑ'IÒIÙ&Ø!Ð-ØÐ*Ø!Ð$6Ò6äØàØ"Ð#8Ð"9ð :'Ø'9Ð&:¸"ð>ðô
ð 	
ô ,Ø×(Ñ(Ø-Ø+Ø5Øõô )ØØ+õð	
õ	
ñ 6°d¸JÓGˆð —‘€JØÐ  T×%5Ñ%5Ð%Aä/Ø×(Ñ(Ø!×2Ñ2Ò8°bô
ˆ
ð *×8Ñ8¸¿¹ÐVZ¸Ó9[Ó\ˆ
äBRÐS`ÓBa×BgÑBg×BnÑBnðØðà/×7Ñ7ÒSÐ;SØ/×7Ñ7ÒSÐ;Sòð Coó C
÷ =
ˆô ˜W k°4Ó8ˆ
ô Cò !ˆÜ�4˜ Ó%Ñ1Ü&Ø Ø Ü˜d EÓ*õô
 �D˜%Õ ð!ô ;ò !ˆÜ�4˜ Ó%Ñ1Ü&Ø Ø Ü˜d EÓ*õô
 �D˜%Õ ð!ð —‘¨dÀ�ÓF€Iä  iÓ0€Iô ,Ø —}‘}Ð%5Ó6Ø+Øõð �yÑ Ø&/§m¡m°LÀ$Ó&Gˆ	Ð"Ñ#ØÐØ!+ˆ	�+Ñð ˜IÑ%Ø+4¯=©=Ð9JÈDÓ+Qˆ	Ð'Ñ(à× Ñ Ð,Ø"3×";Ñ";ˆ	�,ÑØ"3×";Ñ";ˆ	�,Ñð �ÑÝ;à˜tÑ#¨	°&Ñ(9Ð(EÜÐHÔIZ×IkÑIk×IqÑIqÐHrÐsÓtÐtà$Ÿ=™=¨Ó4ˆ	ÙØ%+¨Y°vÑ->Ð$?ˆI�jÒ!à,5°fÑ,=ˆI�jÑ! &Ñ)à�‰�fÔð %6×$?Ñ$?ÔCS×C_ÑC_×CeÑCeÑ$eÐÜ0UØ#Ÿ-™-Ð(;Ó<ØØ#Ø-ô	1÷ +Ð ð $Ð/Ø)Eˆ	Ð%Ñ&Ü
0Ø#Ÿ-™-Ð(;Ó<ØØ-ô÷ ð ô
 2Ø#Ÿ-™-Ð(;Ó<ØØ-ô÷ ð ô ×.Ñ.Ð:ô 	×+Ñ+×/Ñ/Ð0CÔDàð ô
 Ð,¬dÔ3Ø+4¯=©=Ð9LÓ+MÐ!Ø$Ð,Ü-1Ð2LÓ-MˆIÐ)Ò*ÜÐ1´4Ô8Ø0J×0PÑ0PÓ0Rò SÑ,�	Ð,Ø)×4Ñ4°YÐ@QÕRðSô -ØØ#ô÷ €Iô
 ¨¯©°{ÀDÓ)IÕJä
#Ø—-‘- ¨TÓ2Ø#ô÷ ð ô $ D§H¡HÓ
-×-Ð-ð ‡x�xÐ D§H¡H×$7Ñ$7¸Ô$>ÜADÀTÇXÁXÃÐQRÒAR˜DŸH™H R a˜L˜>¨¨d¯h©h°r°s¨m¨_Ñ=ÐX^ˆÜØØÐhÐipÐhqÐrÐsô
ð 	
ð
 ‡x�xÐ¤ D§H¡H£Ô0IÒ IÜØàÐTÔUnÐToð  pAð  Bðô
ð 	
ð ×ÑÐ'ßPáð
 "×+Ñ+°4Ð7ò VØ%×/Ñ/Ô3C×3OÑ3O×3UÑ3UÑUð ð
  $Ð&ò GØ×.Ñ.°dÐ:òGà×(Ñ(¨J×,FÑ,FÑFð %ñ
 #Ñ+CÜ9Ø&7Ø$(×$8Ñ$8Ø"/ô÷ ð ô &4Ø×+Ñ+Ø#5Ø+ô&÷  ˆIð
 Ð Ü#Ø #ØHÈ×I]ÑI]ÐH^Ð_ôð ô (Ø#ØØ+ô÷ ð ô ,Ñ^¸Ð^À)Ñ^ÐX]Ò^×^€Hà"×.Ñ.€Hˆ]Ñä"×1Ñ1°(Ó;€Hà×&Ñ&€H„Nä×ÑÜ×8Ñ8ØØØ/Ø1ô		
ôð €OðG
	
úôT ò 
Ü×"Ñ"ØmÐop÷	
ò 	
ûð
úð=
ùð\+ùðùð
ùð.ùðùð .ùðHùð øðøð _ús#  ‚C5e1Ã7d#Ã8A0e1Å)A	e1Æ3e1Æ9Ee1Ë<d& ÌB+e1Î6eÎ7'e1Ï<e1ÐF e1ÖeÖ+e1×e×	$e1×-e×.B1e1ÚeÚ A e1Û e"Û!e1Û=e%Û>Ee1áe(áe1á0e+á11e1â"e-â#e1â;e/â<A(e1ä&	eä/eåe1åeåe1åe1åe1åe1åe1å"e1å%e1å(e1å+e1å-e1å/e1ÚkeysÚentity_rpm_limitÚentity_tpm_limitÚentity_model_rpm_limit_dictÚentity_model_tpm_limit_dictÚentity_typec                 óx  — t        |dd«      xs* |j                  r|j                  j                  dd«      nd}t        |dd«      xs* |j                  r|j                  j                  dd«      nd}|€|€yi }	i }
| D ]Ï  }|j                  j                  dd«      �J|j                  j                  di «      j                  «       D ]  \  }}|	j                  |d«      |z   |	|<   Œ |j                  j                  dd«      €Œ†|j                  j                  di «      j                  «       D ]  \  }}|
j                  |d«      |z   |
|<   Œ ŒÑ |�³|j                  «       D ]   \  }}|�A|	j                  |d«      |z   |kD  r)t	        dd|	j                  |d«      › d|› d|› d	|› �¬
«      ‚|sŒL|j                  |«      }|sŒ`|	j                  |d«      |z   |kD  sŒyt	        dd|	j                  |d«      › d|› d|› d	|› �¬
«      ‚ |�´|j                  «       D ]   \  }}|�A|
j                  |d«      |z   |kD  r)t	        dd|
j                  |d«      › d|› d|› d|› �¬
«      ‚|sŒL|j                  |«      }|sŒ`|
j                  |d«      |z   |kD  sŒyt	        dd|
j                  |d«      › d|› d|› d|› �¬
«      ‚ yy)z~
    Generic function to check if a key is allocating model specific limits.
    Raises an error if we're overallocating.
    Úmodel_rpm_limitNÚmodel_tpm_limitr   rÓ   úAllocated RPM limit=ú + Key RPM limit=ú is greater than ú RPM limit=r¶   úAllocated TPM limit=ú + Key TPM limit=ú TPM limit=)r8  r  r¹   r¹  r   )rÜ  rž   rÝ  rÞ  rß  rà  rá  rã  rä  Úmodel_specific_rpm_limitÚmodel_specific_tpm_limitrt  Úmodelrg  rf  Úentity_model_specific_rpm_limitÚentity_model_specific_tpm_limits                    r€   Ú _check_key_model_specific_limitsrñ  É  sî  € ô % TÐ+<¸dÓCò Ø6:·m²mˆ�‰×ÑÐ+¨TÔ2Èð ô % TÐ+<¸dÓCò Ø6:·m²mˆ�‰×ÑÐ+¨TÔ2Èð ð Ð ?Ð#:Øð 79ÐØ68Ðàò eˆØ�<‰<×ÑÐ-¨tÓ4Ð@Ø$'§L¡L×$4Ñ$4Ð5FÈÓ$K×$QÑ$QÓ$Sò eÑ ��yØ2J×2NÑ2NÈuÐVWÓ2XÐ[dÑ2dÐ(¨Ò/ðeà�<‰<×ÑÐ-¨tÓ4Ñ@Ø$'§L¡L×$4Ñ$4Ð5FÈÓ$K×$QÑ$QÓ$Sò eÑ ��yØ2J×2NÑ2NÈuÐVWÓ2XÐ[dÑ2dÐ(¨Ò/ñeðeð Ð"Ø /× 5Ñ 5Ó 7ò 	ÑˆE�9ØÐ+Ð0H×0LÑ0LÈUÐTUÓ0VÐYbÑ0bÐeuÒ0uÜ#Ø #Ø1Ð2J×2NÑ2NÈuÐVWÓ2XÐ1YÐYjÐktÐjuð  vGð  HSð  GTð  T_ð  `pð  _qð  rôð ò -Ø2M×2QÑ2QÐRWÓ2XÐ/â3Ø0×4Ñ4°U¸AÓ>ÀÑJÐMlÓlä'Ø$'Ø!5Ð6N×6RÑ6RÐSXÐZ[Ó6\Ð5]Ð]nÐoxÐnyð  zKð  LWð  KXð  Xcð  dCð  cDð   Eôð ð	ð" Ð"Ø /× 5Ñ 5Ó 7ò 	ÑˆE�9ØÐ+Ð0H×0LÑ0LÈUÐTUÓ0VÐYbÑ0bÐeuÒ0uÜ#Ø #Ø1Ð2J×2NÑ2NÈuÐVWÓ2XÐ1YÐYjÐktÐjuð  vGð  HSð  GTð  T_ð  `pð  _qð  rôð ò -Ø2M×2QÑ2QÐRWÓ2XÐ/â3Ø0×4Ñ4°U¸AÓ>ÀÑJÐMlÓlä'Ø$'Ø!5Ð6N×6RÑ6RÐSXÐZ[Ó6\Ð5]Ð]nÐoxÐnyð  zKð  LWð  KXð  Xcð  dCð  cDð   Eôð ñ	ð #r‚   c                 ó†  — | �3t        | «      dkD  r%t        d„ | D «       «      }t        d„ | D «       «      }nd}d}|j                  �7|�5|j                  |z   |kD  r#t        dd|› d|j                  › d|› d	|› �¬
«      ‚|j                  �9|�6|j                  |z   |kD  r#t        dd|› d|j                  › d|› d|› �¬
«      ‚yyy)zw
    Generic function to check if a key is allocating rpm/tpm limits.
    Raises an error if we're overallocating.
    Nr   c              3   óN   K  — | ]  }|j                   €Œ|j                   –— Œ y ­wr|   )rf  ©rB  rt  s     r€   rD  z,_check_key_rpm_tpm_limits.<locals>.<genexpr>  ó   è ø€ ÒW¨c¸S¿]¹]Ñ=V˜CŸM�MÑWùó   ‚%”%c              3   óN   K  — | ]  }|j                   €Œ|j                   –— Œ y ­wr|   )rg  rô  s     r€   rD  z,_check_key_rpm_tpm_limits.<locals>.<genexpr>  rõ  rö  rÓ   ré  rê  rç  rë  r¶   rå  ræ  rè  )r¾  Úsumrf  r   rg  )rÜ  rž   rÝ  rÞ  rá  Úallocated_tpmÚallocated_rpms          r€   Ú_check_key_rpm_tpm_limitsrû    s#  € ð ÐœC ›I¨šMÜÑW°TÔWÓWˆÜÑW°TÔWÓW‰àˆØˆð 	�‰Ð"ØÐ(Ø�N‰N˜]Ñ*Ð-=Ò=äØØ)¨-¨Ð8IÈ$Ï.É.ÐIYÐYjÐkvÐjwð  xCð  DTð  CUð  Vô
ð 	
ð
 	�‰Ð"ØÐ(Ø�N‰N˜]Ñ*Ð-=Ò=äØØ)¨-¨Ð8IÈ$Ï.É.ÐIYÐYjÐkvÐjwð  xCð  DTð  CUð  Vô
ð 	
ð >ð )ð 	#r‚   c           	      óà   — i }i }|j                   r8|j                   j                  di «      }|j                   j                  di «      }t        | ||j                  |j                  ||d¬«       y)zs
    Check if the team key is allocating model specific limits. If so, raise an error if we're overallocating.
    rã  rä  rb  ©rÜ  rž   rÝ  rÞ  rß  rà  rá  N)r  r¹   rñ  rg  rf  )rÜ  rÂ   rž   rß  rà  s        r€   Ú$check_team_key_model_specific_limitsrþ  6  sx   € ð #%ÐØ"$ÐØ×ÒØ&0×&9Ñ&9×&=Ñ&=Ð>OÐQSÓ&TÐ#Ø&0×&9Ñ&9×&=Ñ&=Ð>OÐQSÓ&TÐ#ä$ØØØ#×-Ñ-Ø#×-Ñ-Ø$?Ø$?Øör‚   c                 óL   — t        | ||j                  |j                  d¬«       y)zl
    Check if the team key is allocating rpm/tpm limits. If so, raise an error if we're overallocating.
    rb  ©rÜ  rž   rÝ  rÞ  rá  N)rû  rg  rf  ©rÜ  rÂ   rž   s      r€   Úcheck_team_key_rpm_tpm_limitsr  O  s'   € ô ØØØ#×-Ñ-Ø#×-Ñ-Øör‚   c              ƒ   ó   K  — |j                   dk7  r|j                  dk7  ryt        t        |«      «      j	                  d| j
                  i¬«      ƒ d{  –—† }t        |t        «      r@|j                  �4t        |j                  «      }|D �cg c]  }|j                  |k7  sŒ|‘Œ }}t        || |¬«       t        || |¬«       y7 Œqc c}w ­w)zÎ
    Check if the team key is allocating guaranteed throughput limits. If so, raise an error if we're overallocating.

    Only runs check if tpm_limit_type or rpm_limit_type is "guaranteed_throughput"
    Úguaranteed_throughputNr¿   r`  r  )Útpm_limit_typeÚrpm_limit_typer¤   rg   r›   r¿   r¸  ÚUpdateKeyRequestrt  rY   rÅ  rþ  r  )rÂ   rž   r¥   rÜ  Ú
hashed_keyrt  s         r€   Ú_check_team_key_limitsr	  `  sÏ   è ø€ ð ×ÑÐ5Ò5¸$×:MÑ:MÐQhÒ:hØô
 Ô:¸=ÓIÓJ×TÑTØ˜*×,Ñ,Ð-ð Uó ÷ €Dô
 �$Ô(Ô)¨d¯h©hÐ.BÜ1°$·(±(Ó;ˆ
Ø#Ö?˜ s§y¡y°JÓ'>’Ð?ˆÐ?Ü(ØØØõô
 "ØØØöðúò @ùs*   ‚ACÁCÁ9CÂC	Â$C	Â( CÃ	CÚ_INHERITED_MODEL_SENTINELSÚ
project_idrž  c              ƒ   ó  K  — t        | ||¬«      ƒ d{  –—† }|€t        ddd| › �i¬«      ‚|j                  rbt        |j                  «      dkD  rJ|j                  D ];  }||j                  vsŒ|t        vsŒt        ddd	|› d
|j                  › d| › �i¬«      ‚ d}|j
                  �t        |j
                  dd«      }|j                  �5|�2|j                  |kD  r"t        ddd|j                  › d|› d| › �i¬«      ‚yyy7 Œí­w)aB  
    Validate that key's models and budget respect its project's limits.

    - Key models must be a subset of project models, except the all-team-models / all-proxy-models
      sentinels, which inherit a parent scope and are narrowed by the project at request time
    - Key max_budget must be <= project max_budget
    )r  r¥   rž  Né”  rµ   zProject not found, project_id=r¶   r   rÓ   zModel 'z:' not in project's allowed models. Project allowed models=z. Project: rR  zKey max_budget (z ) exceeds project's max_budget (z). Project: )r.   r   ru   r¾  r
  Úlitellm_budget_tabler8  rR  )r  rž   r¥   rž  Úproject_objÚmÚproject_max_budgets          r€   Ú_check_project_key_limitsr  ‰  sp  è ø€ ô  2ØØ#Ø-ô ÷ €Kð ÐÜØØÐ=¸j¸\ÐJÐKô
ð 	
ð ‡{‚{”s˜;×-Ñ-Ó.°Ò2Ø—‘ò 	ˆAØ˜×*Ñ*Ò*¨qÔ8RÒ/RÜ#Ø #à 7¨1¨#Ð-gÐhs×hzÑhzÐg{ð  |Gð  HRð  GSð  "Tðôð ð	ð ÐØ×'Ñ'Ð3Ü$ [×%EÑ%EÀ|ÐUYÓZÐà‡�Ð"Ð'9Ð'EÈ$Ï/É/Ð\nÒJnÜØàÐ+¨D¯O©OÐ+<Ð<\Ð]oÐ\pÐp|ð  ~Hð  }Ið  Jðô
ð 	
ð KoÐ'EÐ"ð9ús   ‚D”D•ADÁ/DÁ8BDr¥  c           	      ó0  — d}d}i }i }|j                   �,|j                   j                  }|j                   j                  }|j                  r8|j                  j	                  di «      }|j                  j	                  di «      }t        | |||||d¬«       y)z{
    Check if the organization key is allocating model specific limits. If so, raise an error if we're overallocating.
    Nrã  rä  Úorganizationrý  )r  rg  rf  r  r¹   rñ  )rÜ  r¥  rž   rÝ  rÞ  rß  rà  s          r€   Ú#check_org_key_model_specific_limitsr  »  s¨   € ð ÐØÐØ"$ÐØ"$Ðà×%Ñ%Ð1Ø$×9Ñ9×CÑCÐØ$×9Ñ9×CÑCÐà×ÒØ&/×&8Ñ&8×&<Ñ&<Ð=NÐPRÓ&SÐ#Ø&/×&8Ñ&8×&<Ñ&<Ð=NÐPRÓ&SÐ#ä$ØØØ)Ø)Ø$?Ø$?Ø"ör‚   c                 óœ   — d}d}|j                   �,|j                   j                  }|j                   j                  }t        | |||d¬«       y)zt
    Check if the organization key is allocating rpm/tpm limits. If so, raise an error if we're overallocating.
    Nr  r   )r  rg  rf  rû  )rÜ  r¥  rž   rÝ  rÞ  s        r€   Úcheck_org_key_rpm_tpm_limitsr  Ü  sW   € ð ÐØÐà×%Ñ%Ð1Ø$×9Ñ9×CÑCÐØ$×9Ñ9×CÑCÐäØØØ)Ø)Ø"ör‚   r   c              ƒ   ó˜  K  — | j                   €t        t        j                  d¬«      ‚t	        t        |«      «      j                  d| j                   iddi¬«      ƒ d{  –—† }|rt        |dd«      nd}|xs g D �ch c]  }|j                  €Œ|j                  ’Œ }}||vrt        t        j                  d|› �¬«      ‚y7 Œbc c}w ­w)	a  Reject ``/key/update`` requests that point a key at an organization
    the caller does not belong to.

    Mirrors the org-membership rule already enforced on ``/key/list`` in
    ``validate_key_list_check``. Proxy admins are checked at the call site.
    NzNCannot assign a key to an organization without a user_id on the caller's tokenr¶   r�   Úorganization_membershipsT©r�   Úincludez*Caller is not a member of organization_id=)	r�   r   r   ÚHTTP_403_FORBIDDENr¤   rf   ra  r8  r   )rá   r   r¥   Úuser_rowÚmembershipsÚ
membershipÚmember_org_idss          r€   r¿  r¿  õ  sí   è ø€ ð × Ñ Ð(ÜÜ×1Ñ1Øcô
ð 	
ô
 *¬.¸Ó*GÓH×TÑTØÐ+×3Ñ3Ð4Ø+¨TÐ2ð Uó ÷ €Hñ QYœ Ð+EÀtÔLÐ^b€Kà6AÒ6GÀRöØ'1ÈJ×LfÑLfÑLrˆ
×"Ó"ð€Nð ð ˜nÑ,ÜÜ×1Ñ1Ø?ÀÐ?PÐQô
ð 	
ð -ðúò
ùs*   ‚AC
Á CÁ!C
Á>CÂCÂ&C
ÃC
c              ƒ   ó\  K  — t        |dd«      xs* |j                  r|j                  j                  dd«      nd}t        |dd«      xs* |j                  r|j                  j                  dd«      nd}|dk7  r|dk7  ryt        t	        |«      «      j                  d| j                  i¬«      ƒ d{  –—† }t        |t        «      r@|j                  �4t        |j                  «      }|D �cg c]  }|j                  |k7  sŒ|‘Œ }}t        || |¬«       t        || |¬«       y7 Œqc c}w ­w)zÖ
    Check if the organization key is allocating guaranteed throughput limits. If so, raise an error if we're overallocating.

    Only runs check if tpm_limit_type or rpm_limit_type is "guaranteed_throughput"
    r  Nr  r  r   r`  )rÜ  r¥  rž   )r8  r  r¹   r¤   rg   r›   r   r¸  r  rt  rY   rÅ  r  r  )r¥  rž   r¥   r  r  rÜ  r  rt  s           r€   rÀ  rÀ    s/  è ø€ ô $ DÐ*:¸DÓAò Ø59·]²]ˆ�‰×ÑÐ*¨DÔ1Èð ô $ DÐ*:¸DÓAò Ø59·]²]ˆ�‰×ÑÐ*¨DÔ1Èð ð Ð0Ò0°^ÐG^Ò5^Øô Ô:¸=ÓIÓJ×TÑTØ  )×";Ñ";Ð<ð Uó ÷ €Dô
 �$Ô(Ô)¨d¯h©hÐ.BÜ1°$·(±(Ó;ˆ
Ø#Ö?˜ s§y¡y°JÓ'>’Ð?ˆÐ?Ü'ØØØõô
 !ØØØöðúò @ùs*   ‚B1D,Â3D%Â49D,Ã-D'ÄD'Ä D,Ä'D,z/key/generatezkey management)r’  ÚdependenciesÚresponse_modelz�The litellm-changed-by header enables tracking of actions performed by authorized users on behalf of other users, providing an audit trail for accountability)Údescriptionc              ƒ   óð  K  — 	 ddl m} ddlm}m}m} |€1t        t        j                  d|j                  j                  i¬«      ‚t        j                  d«       t        |¬«      ƒ d{  –—†  | j                  �Jt        j                   | j                  «      r| j                  dk  rt        d	dd
| j                  › �i¬«      ‚| j"                  �Jt        j                   | j"                  «      r| j"                  dk  rt        d	dd| j"                  › �i¬«      ‚|}|�rt%        j&                  |«      r || «      ƒ d{  –—† }nt)        d«      ‚|j+                  dd«      }	|j+                  dd«      }
|	st        t        j,                  |
¬«      ‚t/        | j0                  |d| j2                  v ¬«       t5        | |¬«       |j6                  duxr' |j6                  t8        j:                  j                  k(  }|s=| j<                  €1|j<                  | _        t        j>                  d|j<                  «       d}| j@                  �-	 tC        | j@                  |||jD                  d¬«      ƒ d{  –—† }tI        ||| tJ        jL                  ¬«       |�tO        || |¬«      ƒ d{  –—†  | jP                  �!tS        | jP                  | ||¬«      ƒ d{  –—†  tU        | |||¬«      ƒ d{  –—† S 7 �Œ‚7 �Œ°7 Œƒ# tF        $ r=}t        j                  d|«       |st        d	d| j@                  › d�¬«      ‚Y d}~ŒÂd}~ww xY w7 Œ™7 Œn7 ŒY# tF        $ r&}t        jV                  d|«       tY        |«      ‚d}~ww xY w­w)an&  
    Generate an API key based on the provided data.

    Docs: https://docs.litellm.ai/docs/proxy/virtual_keys

    Parameters:
    - duration: Optional[str] - Specify the length of time the token is valid for. You can set duration as seconds ("30s"), minutes ("30m"), hours ("30h"), days ("30d").
    - key_alias: Optional[str] - User defined key alias
    - key: Optional[str] - User defined key value. Must start with 'sk-' and be at least 16 characters long. If not set, a 16-digit unique sk-key is created for you.
    - team_id: Optional[str] - The team id of the key
    - user_id: Optional[str] - The user id of the key
    - agent_id: Optional[str] - The agent id associated with the key.
    - organization_id: Optional[str] - The organization id of the key. If not set, and team_id is set, the organization id will be the same as the team id. If conflict, an error will be raised.
    - project_id: Optional[str] - The project id of the key. When set, models and max_budget are validated against the project's limits.
    - budget_id: Optional[str] - The budget id associated with the key. Created by calling `/budget/new`.
    - models: Optional[list] - Model_name's a user is allowed to call. (if empty, key is allowed to call all models)
    - aliases: Optional[dict] - Any alias mappings, on top of anything in the config.yaml model list. - https://docs.litellm.ai/docs/proxy/virtual_keys#managing-auth---upgradedowngrade-models
    - config: Optional[dict] - any key-specific configs, overrides config in config.yaml
    - spend: Optional[int] - Amount spent by key. Default is 0. Will be updated by proxy whenever key is used. https://docs.litellm.ai/docs/proxy/virtual_keys#managing-auth---tracking-spend
    - send_invite_email: Optional[bool] - Whether to send an invite email to the user_id, with the generate key
    - max_budget: Optional[float] - Specify max budget for a given key.
    - budget_duration: Optional[str] - Budget is reset at the end of specified duration. If not set, budget is never reset. You can set duration as seconds ("30s"), minutes ("30m"), hours ("30h"), days ("30d").
    - max_parallel_requests: Optional[int] - Rate limit a user based on the number of parallel requests. Raises 429 error, if user's parallel requests > x.
    - metadata: Optional[dict] - Metadata for key, store information for key. Example metadata = {"team": "core-infra", "app": "app2", "email": "ishaan@berri.ai" }
    - guardrails: Optional[List[str]] - List of active guardrails for the key
    - policies: Optional[List[str]] - List of policy names to apply to the key. Policies define guardrails, conditions, and inheritance rules.
    - disable_global_guardrails: Optional[bool] - Whether to disable global guardrails for the key.
    - throttle_on_budget_exceeded: Optional[bool] - When the key exceeds its max_budget, throttle its tpm/rpm to the global budget_exceeded_throttle_percentage instead of blocking the key entirely.
    - enable_prompt_caching: Optional[bool] - Auto-inject prompt caching breakpoints (Anthropic cache_control markers) on requests made with this key. Anthropic and Bedrock Claude models only.
    - permissions: Optional[dict] - key-specific permissions. Currently just used for turning off pii masking (if connected). Example - {"pii": false}
    - model_max_budget: Optional[Dict[str, BudgetConfig]] - Model-specific budgets {"gpt-4": {"budget_limit": 0.0005, "time_period": "30d"}}}. IF null or {} then no model specific budget.
    - budget_fallbacks: Optional[Dict[str, List[str]]] - Per-model fallback chain tried in order when that model's own `model_max_budget` is exceeded, e.g. {"gpt-4o": ["gpt-4o-mini"]}.
    - model_rpm_limit: Optional[dict] - key-specific model rpm limit. Example - {"text-davinci-002": 1000, "gpt-3.5-turbo": 1000}. IF null or {} then no model specific rpm limit.
    - model_tpm_limit: Optional[dict] - key-specific model tpm limit. Example - {"text-davinci-002": 1000, "gpt-3.5-turbo": 1000}. IF null or {} then no model specific tpm limit.
    - default_estimated_output_tokens: Optional[int] - Proxy admin only. Expected output tokens reserved for TPM limiting when a request omits max_tokens. Positive integer. Falls back to the team setting, then to the built-in estimate.
    - default_estimated_output_tokens_per_model: Optional[dict] - Proxy admin only. Per-model override of the above. Example - {"gpt-4": 4096, "gpt-3.5-turbo": 1024}. Takes precedence over the key-wide value.
    - mcp_rpm_limit: Optional[dict] - key-specific per-MCP-server rpm limit, keyed by MCP server name (alias if set, else the configured name). Example - {"github": 100, "slack": 200}. IF null or {} then no MCP-specific rpm limit.
    - tag_rpm_limit: Optional[dict] - key-specific per-request-tag rpm limit, keyed by request tag. Example - {"cell-1": 1000, "cell-2": 500}. Each tag gets an independent counter; requests whose tag is absent fall back to the key-level rpm limit.
    - tpm_limit_type: Optional[str] - Type of tpm limit. Options: "best_effort_throughput" (no error if we're overallocating tpm), "guaranteed_throughput" (raise an error if we're overallocating tpm), "dynamic" (dynamically exceed limit when no 429 errors). Defaults to "best_effort_throughput".
    - rpm_limit_type: Optional[str] - Type of rpm limit. Options: "best_effort_throughput" (no error if we're overallocating rpm), "guaranteed_throughput" (raise an error if we're overallocating rpm), "dynamic" (dynamically exceed limit when no 429 errors). Defaults to "best_effort_throughput".
    - allowed_cache_controls: Optional[list] - List of allowed cache control values. Example - ["no-cache", "no-store"]. See all values - https://docs.litellm.ai/docs/proxy/caching#turn-on--off-caching-per-request
    - blocked: Optional[bool] - Whether the key is blocked.
    - rpm_limit: Optional[int] - Specify rpm limit for a given key (Requests per minute)
    - tpm_limit: Optional[int] - Specify tpm limit for a given key (Tokens per minute)
    - soft_budget: Optional[float] - Specify soft budget for a given key. Will trigger a slack alert when this soft budget is reached.
    - tags: Optional[List[str]] - Tags for [tracking spend](https://litellm.vercel.app/docs/proxy/enterprise#tracking-spend-for-custom-tags) and/or doing [tag-based routing](https://litellm.vercel.app/docs/proxy/tag_routing).
    - prompts: Optional[List[str]] - List of prompts that the key is allowed to use.
    - enforced_params: Optional[List[str]] - List of enforced params for the key (Enterprise only). [Docs](https://docs.litellm.ai/docs/proxy/enterprise#enforce-required-params-for-llm-requests)
    - prompts: Optional[List[str]] - List of prompts that the key is allowed to use.
    - allowed_routes: Optional[list] - List of allowed routes for the key. Store the actual route or store a wildcard pattern for a set of routes. Example - ["/chat/completions", "/embeddings", "/keys/*"]
    - allowed_passthrough_routes: Optional[list] - List of allowed pass through endpoints for the key. Store the actual endpoint or store a wildcard pattern for a set of endpoints. Example - ["/my-custom-endpoint"]. Use this instead of allowed_routes, if you just want to specify which pass through endpoints the key can access, without specifying the routes. If allowed_routes is specified, allowed_pass_through_endpoints is ignored.
    - object_permission: Optional[LiteLLM_ObjectPermissionBase] - key-specific object permission. Example - {"vector_stores": ["vector_store_1", "vector_store_2"], "agents": ["agent_1", "agent_2"], "agent_access_groups": ["dev_group"]}. IF null or {} then no object permission.
    - key_type: Optional[str] - Type of key that determines default allowed routes. Options: "llm_api" (can call LLM API routes), "management" (can call management routes), "read_only" (can only call info/read routes), "default" (uses default allowed routes). Defaults to "default".
    - prompts: Optional[List[str]] - List of allowed prompts for the key. If specified, the key will only be able to use these specific prompts.
    - auto_rotate: Optional[bool] - Whether this key should be automatically rotated (regenerated)
    - rotation_interval: Optional[str] - How often to auto-rotate this key (e.g., '30s', '30m', '30h', '30d'). Required if auto_rotate=True.
    - allowed_vector_store_indexes: Optional[List[dict]] - List of allowed vector store indexes for the key. Example - [{"index_name": "my-index", "index_permissions": ["write", "read"]}]. If specified, the key will only be able to use these specific vector store indexes. Create index, using `/v1/indexes` endpoint.
    - router_settings: Optional[UpdateRouterConfig] - key-specific router settings. Example - {"model_group_retry_policy": {"gpt-4": {"RateLimitErrorRetries": 5}}}. IF null or {} then no router settings.
    - access_group_ids: Optional[List[str]] - List of access group IDs to associate with the key. Access groups define which models a key can access. Example - ["access_group_1", "access_group_2"].
    - budget_limits: Optional[list] - List of concurrent budget windows for the key. Each window specifies a budget_limit, time_period, and optional budget_duration. Example - [{"budget_limit": 10.0, "time_period": "1d"}, {"budget_limit": 50.0, "time_period": "7d"}].

    Examples:

    1. Allow users to turn on/off pii masking

    ```bash
    curl --location 'http://0.0.0.0:4000/key/generate'         --header 'Authorization: Bearer sk-1234'         --header 'Content-Type: application/json'         --data '{
            "permissions": {"allow_pii_controls": true}
    }'
    ```

    Returns:
    - key: (str) The generated api key
    - expires: (datetime) Datetime object for when key expires.
    - user_id: (str) Unique user id - used for tracking spend across multiple keys for same user id.
    r   ©r¶  ©r¥   rž  Úuser_custom_key_generateNrµ   r¶   úentered /key/generate©rá   rÓ   ú;max_budget must be a non-negative finite number. Received: z<soft_budget must be a non-negative finite number. Received: ú,user_custom_key_generate must be a coroutineÚdecisionTrÕ   ú(Authentication Failed - Custom Auth Ruler*  ©r*  rá   r>  rƒ  z<key/generate: auto-assigning user_id=%s for non-admin caller©r¿   r¥   rž  Úparent_otel_spanÚcheck_db_onlyú0Error getting team object in `/key/generate`: %súTeam not found for team_id=z<. Non-admin users cannot create keys for non-existent teams.r  ©rÂ   rž   r¥   ©r  rž   r¥   rž  ©rž   rá   ry  rÂ   zDlitellm.proxy.proxy_server.generate_key_fn(): Exception occured - %s)-Úlitellm.proxy._typesr¶  r©  r¥   rž  r(  r   r   ÚHTTP_500_INTERNAL_SERVER_ERRORÚdb_not_connected_errorræ   r   r­  r:   rR  rP  rQ  rd  ÚinspectÚiscoroutinefunctionrµ  r¹   r  rF  r*  r6  r@   rã   rä   rå   r�   rº   r¿   r/   r1  r!  r  ÚKeyManagementRoutesÚKEY_GENERATEr	  r  r  rÛ  Ú	exceptionrZ   )rž   rá   ry  r¶  r¥   rž  r(  Úcustom_key_generate_hookÚresultr-  rÕ   rÙ  rÂ   r#  s                 r€   Úgenerate_key_fnrB  @  s—  è ø€ ð|v+Ý:÷	
ñ 	
ð Ð ÜÜ"×AÑAØÐ!2×!IÑ!I×!OÑ!OÐPôð ô
 	×"Ñ"Ð#:Ô;ä/ÐBSÔT×TÐTð �?‰?Ð&´·±¸d¿o¹oÔ0NÐRV×RaÑRaÐdeÒReÜØØÐ#^Ð_c×_nÑ_nÐ^oÐ!pÐqôð ð ×ÑÐ'´·±¸t×?OÑ?OÔ1PÐTX×TdÑTdÐghÒThÜØØÐ#_Ð`d×`pÑ`pÐ_qÐ!rÐsôð ð %ð 	!ð $Ð/Ü×*Ñ*Ð+CÔDÙ&>¸tÓ&D× D‘ä Ð!OÓPÐPØ$Ÿj™j¨°TÓ:ˆHØ#ŸZ™Z¨	Ð3]Ó^ˆGÙÜ#´×0IÑ0IÐRYÔZÐZä/Ø×.Ñ.Ø/Ø(8¸D×<QÑ<QÐ(Qõ	
ô
 	4ØØ/õ	
ð ×'Ñ'¨tÐ3ò RØ!×+Ñ+Ô/?×/KÑ/K×/QÑ/QÑQð 	ñ  4§<¡<Ð#7Ø,×4Ñ4ˆDŒLÜ ×(Ñ(ØNØ!×)Ñ)ôð
 9=ˆ
Ø�<‰<Ð#ðÜ#2Ø ŸL™LØ"/Ø'9Ø%6×%GÑ%GØ"&ô$÷ �
ô  	Ø!Ø/ØÜ%×2Ñ2õ		
ð Ð!Ü(Ø%ØØ+ô÷ ð ð �?‰?Ð&Ü+ØŸ?™?ØØ+Ø#5ô	÷ ð ô 3ØØ/Ø1Ø!ô	
÷ 
ð 	
ð{ 	Uùð( !EùðDùô ò Ü$×*Ñ*Ð+]Ð_`Ôaá&Ü'Ø$'Ø!<¸T¿\¹\¸Nð  KGð   Hôð ô 'ûðúð"øðøð
ùô ò +Ü×&Ñ&Ð'mÐopÔqÜ'¨Ó*Ð*ûð+üs»   ‚M6„A'M Á+K-Á,CM Å K0ÅDM É'K5 É/K3É0K5 É40M Ê$L>Ê%,M ËM ËM Ë(MË)M Ë,M6Ë-M Ë0M Ë3K5 Ë5	L;Ë>3L6Ì1M Ì6L;Ì;M Í M ÍM Í	M3Í!M.Í.M3Í3M6z/key/service-account/generate)r’  r"  c              ƒ   ó  K  — ddl m} ddlm}m}m} |€1t        t        j                  d|j                  j                  i¬«      ‚t        |¬«      ƒ d{  –—†  t        | j                  |d| j                  v ¬	«       t        | |¬
«       t!        | j"                  |¬«      ƒ d{  –—†  t%        j&                  d«       |}|�rt)        j*                  |«      r || «      ƒ d{  –—† }nt-        d«      ‚|j/                  dd«      }	|j/                  dd«      }
|	st        t        j0                  |
¬«      ‚d}| j"                  �-	 t3        | j"                  |||j4                  d¬«      ƒ d{  –—† }|�t9        || |¬«      ƒ d{  –—†  t;        ||| t<        j>                  ¬«       d| _         tC        | |||¬«      ƒ d{  –—† S 7 �Œn7 �Œ!7 Œå7 Œ_# t6        $ r"}t%        j&                  d|«       d}Y d}~Œƒd}~ww xY w7 Œw7 Œ>­w)aˆ  
    Generate a Service Account API key based on the provided data. This key does not belong to any user. It belongs to the team.

    Why use a service account key?
    - Prevent key from being deleted when user is deleted.
    - Apply team limits, not team member limits to key.

    Docs: https://docs.litellm.ai/docs/proxy/virtual_keys

    Parameters:
    - duration: Optional[str] - Specify the length of time the token is valid for. You can set duration as seconds ("30s"), minutes ("30m"), hours ("30h"), days ("30d").
    - key_alias: Optional[str] - User defined key alias
    - key: Optional[str] - User defined key value. Must start with 'sk-' and be at least 16 characters long. If not set, a 16-digit unique sk-key is created for you.
    - team_id: Optional[str] - The team id of the key
    - user_id: Optional[str] - [NON-FUNCTIONAL] THIS WILL BE IGNORED. The user id of the key
    - budget_id: Optional[str] - The budget id associated with the key. Created by calling `/budget/new`.
    - models: Optional[list] - Model_name's a user is allowed to call. (if empty, key is allowed to call all models)
    - aliases: Optional[dict] - Any alias mappings, on top of anything in the config.yaml model list. - https://docs.litellm.ai/docs/proxy/virtual_keys#managing-auth---upgradedowngrade-models
    - config: Optional[dict] - any key-specific configs, overrides config in config.yaml
    - spend: Optional[int] - Amount spent by key. Default is 0. Will be updated by proxy whenever key is used. https://docs.litellm.ai/docs/proxy/virtual_keys#managing-auth---tracking-spend
    - send_invite_email: Optional[bool] - Whether to send an invite email to the user_id, with the generate key
    - max_budget: Optional[float] - Specify max budget for a given key.
    - budget_duration: Optional[str] - Budget is reset at the end of specified duration. If not set, budget is never reset. You can set duration as seconds ("30s"), minutes ("30m"), hours ("30h"), days ("30d").
    - max_parallel_requests: Optional[int] - Rate limit a user based on the number of parallel requests. Raises 429 error, if user's parallel requests > x.
    - metadata: Optional[dict] - Metadata for key, store information for key. Example metadata = {"team": "core-infra", "app": "app2", "email": "ishaan@berri.ai" }
    - guardrails: Optional[List[str]] - List of active guardrails for the key
    - permissions: Optional[dict] - key-specific permissions. Currently just used for turning off pii masking (if connected). Example - {"pii": false}
    - model_max_budget: Optional[Dict[str, BudgetConfig]] - Model-specific budgets {"gpt-4": {"budget_limit": 0.0005, "time_period": "30d"}}}. IF null or {} then no model specific budget.
    - budget_fallbacks: Optional[Dict[str, List[str]]] - Per-model fallback chain tried in order when that model's own `model_max_budget` is exceeded, e.g. {"gpt-4o": ["gpt-4o-mini"]}.
    - model_rpm_limit: Optional[dict] - key-specific model rpm limit. Example - {"text-davinci-002": 1000, "gpt-3.5-turbo": 1000}. IF null or {} then no model specific rpm limit.
    - model_tpm_limit: Optional[dict] - key-specific model tpm limit. Example - {"text-davinci-002": 1000, "gpt-3.5-turbo": 1000}. IF null or {} then no model specific tpm limit.
    - default_estimated_output_tokens: Optional[int] - Proxy admin only. Expected output tokens reserved for TPM limiting when a request omits max_tokens. Positive integer. Falls back to the team setting, then to the built-in estimate.
    - default_estimated_output_tokens_per_model: Optional[dict] - Proxy admin only. Per-model override of the above. Example - {"gpt-4": 4096, "gpt-3.5-turbo": 1024}. Takes precedence over the key-wide value.
    - mcp_rpm_limit: Optional[dict] - key-specific per-MCP-server rpm limit, keyed by MCP server name (alias if set, else the configured name). Example - {"github": 100, "slack": 200}. IF null or {} then no MCP-specific rpm limit.
    - tpm_limit_type: Optional[str] - TPM rate limit type - "best_effort_throughput", "guaranteed_throughput", or "dynamic"
    - rpm_limit_type: Optional[str] - RPM rate limit type - "best_effort_throughput", "guaranteed_throughput", or "dynamic"
    - allowed_cache_controls: Optional[list] - List of allowed cache control values. Example - ["no-cache", "no-store"]. See all values - https://docs.litellm.ai/docs/proxy/caching#turn-on--off-caching-per-request
    - blocked: Optional[bool] - Whether the key is blocked.
    - rpm_limit: Optional[int] - Specify rpm limit for a given key (Requests per minute)
    - tpm_limit: Optional[int] - Specify tpm limit for a given key (Tokens per minute)
    - soft_budget: Optional[float] - Specify soft budget for a given key. Will trigger a slack alert when this soft budget is reached.
    - tags: Optional[List[str]] - Tags for [tracking spend](https://litellm.vercel.app/docs/proxy/enterprise#tracking-spend-for-custom-tags) and/or doing [tag-based routing](https://litellm.vercel.app/docs/proxy/tag_routing).
    - enforced_params: Optional[List[str]] - List of enforced params for the key (Enterprise only). [Docs](https://docs.litellm.ai/docs/proxy/enterprise#enforce-required-params-for-llm-requests)
    - allowed_routes: Optional[list] - List of allowed routes for the key. Store the actual route or store a wildcard pattern for a set of routes. Example - ["/chat/completions", "/embeddings", "/keys/*"]
    - object_permission: Optional[LiteLLM_ObjectPermissionBase] - key-specific object permission. Example - {"vector_stores": ["vector_store_1", "vector_store_2"], "agents": ["agent_1", "agent_2"], "agent_access_groups": ["dev_group"]}. IF null or {} then no object permission.
    Examples:
    - allowed_vector_store_indexes: Optional[List[dict]] - List of allowed vector store indexes for the key. Example - [{"index_name": "my-index", "index_permissions": ["write", "read"]}]. If specified, the key will only be able to use these specific vector store indexes. Create index, using `/v1/indexes` endpoint.


    1. Allow users to turn on/off pii masking

    ```bash
    curl --location 'http://0.0.0.0:4000/key/generate'         --header 'Authorization: Bearer sk-1234'         --header 'Content-Type: application/json'         --data '{
            "permissions": {"allow_pii_controls": true}
    }'
    ```

    Returns:
    - key: (str) The generated api key
    - expires: (datetime) Datetime object for when key expires.
    - user_id: (str) Unique user id - used for tracking spend across multiple keys for same user id.

    r   r&  r'  Nrµ   r¶   r*  r*  r/  rƒ  r�  r)  r,  r-  TrÕ   r.  r0  r3  r5  r  r7  )"r8  r¶  r©  r¥   rž  r(  r   r   r9  r:  ræ   r:   rF  r*  r6  r@   rc  r¿   r   r­  r;  r<  rµ  r¹   r  r/   r1  r!  r	  r  r=  ÚKEY_GENERATE_SERVICE_ACCOUNTr�   rÛ  )rž   rá   ry  r¶  r¥   rž  r(  r@  rA  r-  rÕ   rÂ   r#  s                r€   Úgenerate_service_account_key_fnrE    s  è ø€ õ` 7÷ñ ð ÐÜÜ×=Ñ=ØÐ.×EÑE×KÑKÐLô
ð 	
ô
 ,Ð>OÔ
P×PÐPä+Ø×*Ñ*Ø+Ø$4¸×8MÑ8MÐ$Mõô
 0ØØ+õô
 ;Ø—‘Ø#ô÷ ð ô
 ×ÑÐ6Ô7à]uÐØÐ+Ü×&Ñ&Ð'?Ô@Ù":¸4Ó"@×@‰FäÐKÓLÐLØ Ÿ*™* Z°Ó6ˆØŸ™ IÐ/YÓZˆÙÜ¬F×,EÑ,EÈgÔVÐVØ48€JØ‡|�|Ðð
	Ü.ØŸ™Ø+Ø#5Ø!2×!CÑ!CØ"ô ÷ ˆJð ÐÜ$Ø!ØØ'ô
÷ 	
ð 	
ô ØØ+ØÜ!×>Ñ>õ	ð €D„Lä.ØØ+Ø-Øô	÷ ð ðw Qùðùð Aøðùô ò 	Ü ×&Ñ&Ð'YÐ[\Ô]Ø�Jûð	úð
	
øðús’   ‚AG?ÁGÁAG?Â%GÂ&=G?Ã#G	Ã$AG?Å'G Å+GÅ,G Å0G?ÆG;Æ:G?Æ>G=Æ?G?ÇG?Ç	G?ÇG Ç	G8ÇG3Ç.G?Ç3G8Ç8G?Ç=G?Únon_default_valuesr~  c                 ó~  — t        |j                  d«      «       d|vr|j                  «       |d<   t        t        |d   «      }t
        D ]9  }|j                  |«      }|€Œ|�||v r||   |k7  rt        d|› d�¬«      ‚|||<   Œ; | j                  dd¬«      }	 |j                  «       D ]T  \  }}|t        v r)t        |t        «      r|j                  «       ||<   n|||<   |t        v sŒ@dd	lm}	 |r |	|«       |||<   ŒV 	 t'        |«      |d<   |S # t         $ r }
t#        j$                  d
|
«       Y d}
~
Œ4d}
~
ww xY w)zu
    Check LiteLLM_ManagementEndpoint_MetadataFields (proxy/_types.py) for fields that are allowed to be updated
    r  NrÓ   z8 is immutable once set and cannot be changed via update.r¶   TrŽ  r   )Ú_premium_user_checkzLlitellm.proxy.proxy_server.prepare_metadata_fields(): Exception occured - %s)r  r¹   Úcopyr   rŒ   Ú LiteLLM_Reserved_Metadata_Fieldsr   r‰   r¹  r´  r¸  r   Ú	isoformatr²  Úlitellm.proxy.utilsrH  r!  r   r?  r7   )rž   rF  r~  Úcasted_metadataÚreserved_fieldÚexisting_valuer&  ÚkÚvrH  r#  s              r€   Úprepare_metadata_fieldsrR  ·  sy  € ô (Ð(:×(>Ñ(>¸zÓ(JÔKàÐ+Ñ+Ø):×)?Ñ)?Ó)AÐ˜:Ñ&ä!¤$Ð(:¸:Ñ(FÓG€Oô ;ò 9ˆØ*×.Ñ.¨~Ó>ˆØÐ!ØØÐ"Ø˜oÑ-°/À.Ñ2QÐUcÒ2cäØØ(Ð)Ð)aÐbôð ð +9ˆ˜Ò'ð9ð .2¯_©_È4Ð^b¨_Ó-c€Ið
Ø—O‘OÓ%ò 	'‰DˆAˆqØÔ=Ñ=Ü˜a¤Ô*Ø)*¯©«�O AÒ&à)*�O AÑ&ØÔEÒEÝCáÙ'¨Ô*Ø%&� Ò"ñ	'ô$ &;¸?Ó%KÐ�zÑ"ØÐøô ò 
Ü×&Ñ&ØZÐ\]÷	
ñ 	
ûð
ús   ÂAD Ã+D Ä	D<ÄD7Ä7D<c           	   ƒ   ó´  K  — | j                  d¬«      }|j                  dd «       |j                  dd «       |j                  dd «       | j                  �B| j                  j                  d«      �'| j                  xs |j                  €t        dd¬	«      ‚i }t        D ](  }t        | |d «      €Œt        | |t        | |«      ¬
«       Œ* |j                  «       D ]  \  }}|t        v s|t        v rŒ|||<   Œ d|v r|j                  d«      }|�|dk(  rd |d<   na|r_t        |t        «      rOt        |«      dkD  rAt        |¬«      }t        j                   t"        j$                  «      t'        |¬«      z   }	|	|d<   d|v rU|j                  d«      }
|
€d |d<   d |d<   n7t        |
t        «      r't        |
«      dkD  rddlm}  ||
¬«      }||d<   |
|d<   d|v r—|d   }|rxddlm} g }|D ]R  }t        |t,        «      r|n|j                  «       } ||d   ¬«      j/                  «       |d<   |j1                  |«       ŒT t3        j4                  |«      |d<   nt3        j4                  d «      |d<   d|v rt7        ||¬«      ƒ d {  –—† }|j                  xs i }d|v rt9        |d   «       d|v r|d   �t;        |d   «      |d<   t=        | ||¬«      }|S 7 ŒP­w)NTrú   rt  Únew_keyÚgrace_periodr€  rÓ   r_  r¶   r‹  rk  rm  Úexpiresr   rl  rÉ   rj  Úbudget_reset_atr;   ©rj  rK  Úreset_atr  )r&  r4  r…  Úrouter_settings)rž   rF  r~  )r‰   r-  r  r¹   r¿   r   r²  r8  rC   r¹  r´  r¸  r’   r¾  r    r   rË   r	   rÌ   r   Ú)litellm.proxy.common_utils.timezone_utilsr<   rŒ   rK  Úappendr°  ÚdumpsÚ _handle_update_object_permissionÚvalidate_model_max_budgetr!   rR  )rž   r4  r&  rF  rÐ  rP  rQ  rk  Ú
duration_srV  rj  r<   Úkey_reset_atÚraw_windowsÚinitialized_windowsÚwindowrT  rÑ  s                     r€   Úprepare_key_update_datare  ê  s.  è ø€ ð "Ÿ_™_¸4˜_Ó@€IØ‡M�M�%˜ÔØ‡M�M�)˜TÔ"Ø‡M�M�. $Ô'à�‰Ð!Ø�M‰M×ÑÐ2Ó3Ð?Ø�\‰\Ò5Ð-×5Ñ5Ð>äØØpô
ð 	
ð Ðô Cò ˆÜ�4˜ Ó%Ñ1Ü&Ø Ø Ü˜d EÓ*öðð —‘Ó!ò "‰ˆˆ1ØÔ9Ñ9¸QÔBsÑ=sØØ !Ð˜1Òð"ð
 Ð'Ñ'Ø,×0Ñ0°Ó<ˆØÐ˜x¨4Ò/à,0Ð˜yÒ)Ùœ: h´Ô4¼#¸h»-È!Ò:KÜ 3¸XÔ FˆJÜ%Ÿ\™\¬(¯,©,Ó7¼)ÈJÔ:WÑWˆGØ,3Ð˜yÑ)àÐ.Ñ.Ø!3×!7Ñ!7Ð8IÓ!JˆØÐ"Ø48ÐÐ0Ñ1Ø48ÐÐ0Ò1Ü˜¬Ô-´#°oÓ2FÈÒ2JÝWá"7ÈÔ"XˆLØ4@ÐÐ0Ñ1Ø4CÐÐ0Ñ1àÐ,Ñ,Ø/°Ñ@ˆÙÝWà)+ÐØ%ò .�Ü(¨´Ô6‘F¸F×<MÑ<MÓ<O�Ù 5ÀaÐHYÑFZÔ [× eÑ eÓ g��*‘Ø#×*Ñ*¨1Õ-ð.ô 37·*±*Ð=PÓ2QÐ˜Ò/ô 37·*±*¸TÓ2BÐ˜Ñ/àÐ0Ñ0Ü#CØ(Ø-ô$
÷ 
Ðð
 (×0Ñ0Ò6°B€Ið Ð/Ñ/Ü!Ð"4Ð5GÑ"HÔIð Ð.Ñ.Ð3EÐFWÑ3XÐ3dÜ0:Ð;MÐN_Ñ;`Ó0aÐÐ,Ñ-ä0ØÐ&8ÈIôÐð Ðð'
ús   ‚B/KÂ2GKÊKÊAKc              ƒ   ó˜   K  — ddl m} t        | |j                  |¬«      ƒ d{  –—† }|�|| d<   t	        j
                  d|«       | S 7 Œ#­w)z1
    Handle the update of object permission.
    r   r§   )r&  Úexisting_object_permission_idr¥   NÚobject_permission_idz updated object_permission_id: %s)r©  r¥   rO   rh  r   r­  )r&  r4  r¥   rh  s       r€   r^  r^  G  s]   è ø€ õ 9ô )OØØ&6×&KÑ&KØ#ô)÷ #Ðð Ð'Ø,@ˆ	Ð(Ñ)Ü×"Ñ"Ð#EÐG[Ô\àÐð#ús   ‚"A
¤A¥$A
c                 óh   — | j                   €y|j                   €y| j                   |j                   k7  S )NFTr¾   ©rž   r4  s     r€   Úis_different_teamrk  _  s4   € Ø‡|�|ÐØØ×ÑÐ'ØØ�<‰<Ð+×3Ñ3Ñ3Ð3r‚   rR  c                 ób   — | �-t        j                  | «      r| dk  rt        ddd| › �i¬«      ‚yy)z±
    Validate that max_budget is not negative.

    Args:
        max_budget: The max_budget value to validate

    Raises:
        HTTPException: If max_budget is negative
    Nr   rÓ   rµ   r+  r¶   )rP  rQ  r   rV  s    r€   Ú_validate_max_budgetrm  g  sH   € ð Ð¤t§}¡}°ZÔ'@ÀJÐQRÂNÜØØÐZÐ[eÐZfÐgÐhô
ð 	
ð ESÐr‚   rÅ  rÒ   c              ƒ   óÈ  K  — |€t        dddi¬«      ‚| �lt        | ¬«      }t        t        |«      «      j	                  d|idd	i¬
«      ƒ d{  –—† }|€+t        dt        j                  dt        j                  ¬«      ‚|S |€+t        dt        j                  dt        j                  ¬«      ‚t        t        |«      «      j                  d|id¬«      ƒ d{  –—† }t        |«      dk(  r/t        d|› d�t        j                  dt        j                  ¬«      ‚t        |«      dkD  r/t        d|› d�t        j                  dt        j                  ¬«      ‚|d   S 7 �Œ7 Œ†­w)a–  
    Get existing key from database and validate it exists.

    Args:
        token: The key token to look up
        prisma_client: Prisma client instance
        key_alias: Alias to look the key up by when token is not provided

    Returns:
        LiteLLM_VerificationToken: The existing key row

    Raises:
        ProxyException: 404 if key is not found, 400 if the alias matches multiple keys
    Nr  rµ   úDatabase not connectedr¶   ©rÅ  rÅ  r  Tr  úKey not found.rt  rÔ   z(either key or key_alias must be providedrÒ   é   )r�   Útaker   z&Key not found. No key with key_alias='z'.é   zMultiple keys share key_alias='z)', so it cannot be used as an identifier.)r   rY   r¤   rg   ra  rÝ   rÞ   Únot_found_errorr   ÚHTTP_404_NOT_FOUNDrß   ÚHTTP_400_BAD_REQUESTr›   r¾  )rÅ  r¥   rÒ   Úhashed_tokenr4  Úrowss         r€   Ú_get_and_validate_existing_keyrz  x  s‹  è ø€ ð" ÐÜØØÐ5Ð6ô
ð 	
ð
 ÐÜ3¸%Ô@ˆäJWÜ'¨Ó6óK
ç
‰+˜W lÐ3Ð>QÐSWÐ=Xˆ+Ó
Y÷EZÐð Ð#Ü Ø(Ü$×4Ñ4ØÜ×.Ñ.ô	ð ð  ÐàÐÜØ>Ü ×2Ñ2ØÜ×,Ñ,ô	
ð 	
ô 7DÜ# MÓ2ó7ç�i�{ IÐ.°Q€iÓ7÷18€Dô ˆ4ƒy�A‚~ÜØ<¸Y¸KÀrÐJÜ ×0Ñ0ØÜ×*Ñ*ô	
ð 	
ô ˆ4ƒy�1‚}ÜØ5°i°[Ð@iÐjÜ ×2Ñ2ØÜ×,Ñ,ô	
ð 	
ð �‰7€NðUEZùð,18ús&   ‚AE"ÁEÁB
E"ÃE ÃBE"Å E"c                 ó¸   — | j                   �| j                   S |j                  €+t        dt        j                  dt
        j                  ¬«      ‚|j                  S )Nrq  rt  rÔ   )rt  rÅ  rÝ   rÞ   ru  r   rv  rj  s     r€   Ú_resolve_token_to_updater|  ¿  sT   € Ø‡x�xÐØ�x‰xˆØ×ÑÐ%ÜØ$Ü ×0Ñ0ØÜ×*Ñ*ô	
ð 	
ð ×!Ñ!Ð!r‚   Úupdate_key_requestÚproxy_logging_objÚuser_custom_key_updatec	           	   ƒ   ó&  K  — t        | j                  «       t        | |¬«       |€t        | j                  |¬«      ƒ d{  –—† }t        | |j                  |d¬«       |�0t        j                  |t        j                  |||¬«      ƒ d{  –—†  |�rt        j                  |«      r || «      ƒ d{  –—† }	nt        d«      ‚|	j                  dd	«      }
|	j                  d
d«      }|
st        t         j"                  |¬«      ‚t%        | d¬«       d}| j&                  �;t)        | j&                  ||d	¬«      ƒ d{  –—† }|�|�t+        || |¬«      ƒ d{  –—†  t-        | |¬«      r9|€t        dddi¬«      ‚|€t        dddi¬«      ‚t/        ||||¬«      ƒ d{  –—†  t1        | |¬«      ƒ d{  –—† }|€t        dddi¬«      ‚i |¥d| j                  i¥}t3        d|j5                  | j                  |¬«      ƒ d{  –—† «      }t7        t9        | j                  «      ||¬«      ƒ d{  –—†  t;        |t9        t=        | |¬«      «      | |¬«      ƒ d{  –—†  t?        j@                  tC        jD                  | ||||¬«      «       |€t        d«      ‚|j                  d i «      }tG        |d!«      r|jI                  «       }ntG        |d"«      r|jK                  «       }|jM                  dd«       |S 7 �Œ´7 �Œl7 �ŒH7 �ŒÂ7 �Œ«7 �Œh7 �ŒV7 �Œ7 Œà7 Œ·­w)#ad  
    Process a single key update with all validations and checks.

    This function encapsulates all the logic for updating a single key,
    including validation, permission checks, team checks, and database updates.

    Args:
        update_key_request: Fully-constructed UpdateKeyRequest for the target key
        user_api_key_dict: The authenticated user's API key info
        litellm_changed_by: Optional header for tracking who made the change
        prisma_client: Prisma client instance
        user_api_key_cache: User API key cache
        proxy_logging_obj: Proxy logging object
        llm_router: LLM router instance
        existing_key_row: Optional pre-fetched key row to avoid redundant lookups

    Returns:
        Dict containing the updated key information

    Raises:
        HTTPException: For various validation and permission errors
    rƒ  N)rÅ  r¥   rt  r}  ©rá   rì   r¥   r4  rž  ú*user_custom_key_update must be a coroutiner-  TrÕ   r.  r¶   Fr‚  ©r¿   r¥   rž  r2  r5  rj  rÓ   rµ   úeLLM router not found. Please set it up by passing in a valid config.yaml or adding models via the UI.r  ú0Team object not found for team change validation©rt  rb  Úchange_initiated_byr  ro  rÅ  zMapping[str, object] | None©rÅ  rž   ©rx  rž  r~  ©r¥   Ú	key_tokenrž   r4  ©rž   r4  r¨  rá   ry  ú(Failed to update key got response = Nonerž   r‰   rŒ   )'rm  rR  rJ  rz  rt  r1   r  rS   Ú/can_team_member_execute_key_management_endpointr=  Ú
KEY_UPDATEr;  r<  rµ  r¹   r   r   r  rx  r¿   r/   r	  rk  Úvalidate_key_team_changere  r   Úupdate_datar+   rY   rK   r|  rÆ  rÇ  r>   Úasync_key_updated_hookÚhasattrr‰   rŒ   r-  )r}  rá   ry  r¥   rž  r~  r  r  r4  rA  r-  rÕ   r”  rF  Ú_datar¨  Úupdated_key_infos                    r€   Ú_process_single_key_updater–  Ì  s“  è ø€ ôD Ð+×6Ñ6Ô7ä(ØØ+õð ÐÜ!?Ø$×(Ñ(Ø'ô"
÷ 
Ðô
 5ØØ*×3Ñ3Ø+Øõ	ð Ð Ü(×XÑXØ/Ü%×0Ñ0Ø'Ø-Ø1ô
÷ 	
ð 	
ð Ð)Ü×&Ñ&Ð'=Ô>Ù"8Ð9KÓ"L×L‰FäÐIÓJÐJØ Ÿ*™* Z°Ó6ˆØŸ™ IÐ/YÓZˆÙÜ¬F×,EÑ,EÈgÔVÐVô #Ð#5ÀUÕKð 37€HØ×!Ñ!Ð-Ü(Ø&×.Ñ.Ø'Ø1Øô	
÷ 
ˆð Ð MÐ$=Ü(Ø#Ø'Ø+ô÷ ð ô Ð0ÐCSÕTØÐÜØàð  Eðôð ð ÐÜØØÐ!SÐTôð ô 'Ø ØØ 1Ø!ô	
÷ 	
ð 	
ô  7Ð<NÐaqÔr×rÐð ÐÜØØÐ5Ð6ô
ð 	
ð
 KÐ(ÐJ¨'Ð3E×3IÑ3IÑJ€EÜ37Ø%Ø×'Ñ'Ð.@×.DÑ.DÈ5Ð'ÓQ×Qó4€Hô #Ü*Ð+=×+AÑ+AÓBØ-Ø+ô÷ ð ô 2Ø#Ü'Ü$Ð*<ÐO_Ô`ó
ð  Ø)ô÷ ð ô ×ÑÜ×6Ñ6Ø#Ø-ØØ/Ø1ô	
ôð ÐÜÐCÓDÐDð  —|‘| F¨BÓ/ÐÜÐ Ô.Ø+×6Ñ6Ó8ÑÜ	Ð! 6Ô	*Ø+×0Ñ0Ó2Ðà×Ñ˜ $Ô'àÐðG
ùð	
ùð Mùð
ùðùð(	
ùð sùð 	Rùðøðús¸   ‚?LÁK5ÁA
LÂK8Â&LÂ3K;Â4BLÄ<K>Ä=LÅLÅALÆLÆLÆ1LÆ2ALÇ?L

È ,LÈ,LÈ-*LÉLÉBLË8LË;LË>LÌLÌLÌLÌ
LÌLÌLr  r”  ÚLiteLLM_TeamTableCachedObjr•  c              ƒ   ó   K  — |}|€-|j                   r!t        |j                   ||d¬«      ƒ d{  –—† }t        | j                  «      }| j                   du xs | j                   |j                   k(  }t	        |||||r|j                  nd¬«      ƒ d{  –—† }	t        |||¬«      ƒ d{  –—†  t        |||¬«      ƒ d{  –—†  |	S 7 Œ–7 Œ47 Œ 7 Œ­w)zEValidate MCP servers in object_permission against the effective team.NTrƒ  )r  r”  r¥   r•  Úexisting_key_object_permissionr–  )r¿   r/   r  r  rP   rQ   rR   )
rž   r”  r4  r¥   rž  r•  Úeffective_team_objÚobject_permission_dictÚteam_unchangedrÓ  s
             r€   Ú$_validate_mcp_servers_for_key_updater�  }	  sù   è ø€ ð "ÐàÐ!Ð&6×&>Ò&>Ü#2Ø$×,Ñ,Ø'Ø1Øô	$
÷ 
Ðô %?¸t×?UÑ?UÓ$VÐØ ŸL™L¨DÐ0Ò\°D·L±LÐDT×D\ÑD\Ñ4\€NÜ0UØ0Ø#Ø#Ø%ÙM[Ð'7×'IÒ'IÐaeô1÷ +Ð ô 1Ø0Ø#Ø%ô÷ ð ô
 2Ø0Ø#Ø%ô÷ ð ð
 (Ð'ð3
øð+øðøð
úsF   ‚-C¯C°A#CÂCÂCÂ)C
Â*CÂ?CÃ CÃCÃ
CÃCc              ƒ   óˆ	  K  — t        | j                  «       t        | j                  «       |j                  t
        j                  j                  k(  }t        | j                  |d| j                  v ¬«       t        | |¬«       t        | |¬«       t        | ||¬«       t        || |j                  ||¬«       t!        j"                  |t$        j&                  |||¬«      ƒ d{  –—†  | j(                  duxr | j(                  |j(                  k7  xs | j                  duxs d| j                  v }t+        |d	d«      }	t-        |	t.        «      r|	j1                  d
«      nd}
| j2                  du r|
dur|st5        dddi¬«      ‚t7        | t-        |	t.        «      r|	nd|d¬«       t9        | t-        |	t.        «      r|	nd|d¬«       |j                  duxr6 t+        |dd«      |j                  k(  xr t+        |dd«      |j                  k(  }t+        |dd«      du}|xs |xr | }|s,|�*|s(|j:                  }t=        |||||rdnd¬«      ƒ d{  –—†  d}| j>                  xs t+        |dd«      }|�ZtA        |||d¬«      ƒ d{  –—† }|€)| j>                  �|st5        dd| j>                  › d�¬«      ‚|�tC        || |¬«      ƒ d{  –—†  t!        jD                  ||| jF                  ¬«       t+        | dd«      xs t+        |dd«      }|�/| jH                  €| j(                  �tK        || ||¬«      ƒ d{  –—†  t+        |d d«      }| jL                  �1| jL                  |k7  r"|s tO        || jL                  |¬!«      ƒ d{  –—†  | jL                  xs |}| jL                  duxs> | jP                  duxs. | jR                  duxs | jT                  duxs | jV                  du}|�@|r>tY        |||¬"«      ƒ d{  –—† }|€t5        dd#|› �¬«      ‚t[        || |¬$«      ƒ d{  –—†  t]        | |¬%«      r9|€t5        ddd&i¬«      ‚|€t5        d'dd(i¬«      ‚t_        ||||¬)«      ƒ d{  –—†  | j`                  �-tc        | |||||¬*«      ƒ d{  –—† }|�te        d+i |¤Ž| _0        yyy7 �ŒÃ7 �ŒZ7 �Œ'7 �Œç7 �Œ{7 �Œ47 Œ¾7 Œ˜7 ŒT7 Œ1­w),z4Validate permissions and constraints for key update.r*  r/  rƒ  ©rž   r4  rá   )rá   rž   r�   r  r  r�  NrK  r  rª  Tr´   rµ   r|  r¶   rt  r}  rˆ  r�   r¿   z/key/update (max_budget/spend)ú/key/update©rá   rx  r¥   rž  rì   rƒ  rÓ   r4  z8. Non-admin users cannot set keys to non-existent teams.r5  r  r  r6  r   rŸ  r¡  r£  r¤  rj  r„  r  r…  r†  )rž   r”  r4  r¥   rž  r•  r}   )3rG   ÚspendrF   rj  rã   rä   rå   ræ   rF  r*  r6  r@   rJ  r=  r$  r�   rS   rŽ  r=  r�  rR  r8  r¸  rŒ   r¹   rª  r   r2   r1   rÅ  Ú_check_key_admin_accessr¿   r/   r	  r  r  ru   r  r   r¿  rf  rg  r  r  r-   rÀ  rk  r�  r  r�  ÚLiteLLM_ObjectPermissionBase)rž   r4  rá   r  r  r¥   rž  rÙ  Ú_is_budget_changeÚ_existing_metadataÚ_existing_throttleÚcaller_is_creatorÚ_key_is_team_keyÚcan_skip_admin_checkr  r”  Ú_team_id_to_checkÚ_project_id_to_checkÚ_existing_org_idÚ_org_id_to_checkÚ_throughput_fields_changedr¥  rÓ  s                          r€   Ú_validate_update_key_datar°  ¥	  sÖ  è ø€ ô ˜$Ÿ*™*Ô%Ü˜T×1Ñ1Ô2à.×8Ñ8Ô<L×<XÑ<X×<^Ñ<^Ñ^€Oä+Ø×*Ñ*Ø+Ø$4¸×8MÑ8MÐ$Mõô
 0ØØ+õô )ØØ+õô
 .ØØ)Ø+õô Ø+ØØ ×(Ñ(ØØ!õô %×
TÑ
TØ+Ü!×,Ñ,Ø#Ø)Ø-ô÷ ð ðP 
�‰ Ð	$Ò	W¨¯©Ð<L×<WÑ<WÑ)Wò 	4Ø�:‰:˜TÐ!ò	4à˜d×3Ñ3Ð3ð ô !(Ð(8¸*ÀdÓ KÐäAKÐL^Ô`dÔAeÐ×ÑÐ<Ô=Ðkoð ð ×'Ñ'¨4Ñ/Ð4FÈdÑ4RÑ[jÜØØÐaÐbô
ð 	
ô
 2ØÜ0:Ð;MÌtÔ0TÑ,ÐZ^Ø+Øõ	ô 5ØÜ0:Ð;MÌtÔ0TÑ,ÐZ^Ø+Øõ	ð 	×!Ñ!¨Ð-ò 	TÜÐ$ l°DÓ9Ð=N×=VÑ=VÑVò	TäÐ$ i°Ó6Ð:K×:SÑ:SÑSð ô &Ð&6¸	À4ÓHÐPTÐTÐØ#4Ò#HÐ8HÒ"cÐRcÐNcÐÙ Ð!:ÑCWØ,×2Ñ2ˆ
Ü%Ø/Ø#Ø'Ø1Ù7HÑ3Èmô
÷ 	
ð 	
ð 37€HØ#Ÿ|™|ÒY¬wÐ7GÈÐTXÓ/YÐØÐ$Ü(Ø%Ø'Ø1Øô	
÷ 
ˆð Ð §¡Ð 8ÁÜØØ4°T·\±\°NÐBzÐ{ôð ð
 ÐÜ(Ø#ØØ+ô÷ ð ô ×FÑFØ+ØØ×.Ñ.õô #*¨$°¸dÓ"CÒ"tÄwÐO_ÐamÐosÓGtÐØÐ'¨T¯[©[Ð-DÈÏÉÐHcÜ'Ø+ØØ'Ø1ô	
÷ 	
ð 	
ô &Ð&6Ð8IÈ4ÓPÐØ×ÑÐ'¨D×,@Ñ,@ÐDTÒ,TÑ]lÜ1Ø/Ø ×0Ñ0Ø'ô
÷ 	
ð 	
ð #×2Ñ2ÒFÐ6FÐà×Ñ DÐ(ò 	+Ø�>‰> Ð%ò	+à�>‰> Ð%ò	+ð ×Ñ dÐ*ò	+ð ×Ñ dÐ*ð ð Ð#Ñ(BÜ!/Ø#Ø1Ø'ô"
÷ 
ˆ	ð
 ÐÜØØDÐEUÐDVÐWôð ô $ØØØ'ô
÷ 	
ð 	
ô ˜dÐ5EÕFØÐÜØàð  Eðôð ð ÐÜØØÐ!SÐTôð ô 'Ø ØØ 1Ø!ô	
÷ 	
ð 	
ð ×ÑÐ)Ü4XØØØ-Ø'Ø1Ø*ô5
÷ /
Ð$ð (Ð3Ü%AÑ%aÐD`Ñ%aˆDÕ"ð 4ð *ðKùðl	
ùð
ùðùð	
ùð	
ùð 
øð	
øð(	
øð/
úsº   ‚C#SÃ%R(Ã&E+SÉR+É5SÊR.ÊASË
R1ËA.SÌ9R4Ì:A	SÎR7ÎA7SÏ;R:Ï<'SÐ#R<Ð$ASÑ)R>Ñ*$SÒS ÒSÒ+SÒ.SÒ1SÒ4SÒ7SÒ:SÒ<SÒ>SÓ Sr   Úrequestc              ƒ   ó�  K  — ddl m}m}m}m}m}m}	 	 |j                  �Jt        j                  |j                  «      r|j                  dk  rt        ddd|j                  › �i¬«      ‚t        |j                  ||j                  ¬«      ƒ d{  –—† }
t        ||
¬	«      }||_        t        ||
|||||¬
«      ƒ d{  –—†  |	}|�rt!        j"                  |«      r ||«      ƒ d{  –—† }nt%        d«      ‚|j'                  dd«      }|j'                  dd«      }|st        t(        j*                  |¬«      ‚t-        |d¬«       t/        ||
¬	«      ƒ d{  –—† }|j'                  dd«      }||
j                  k7  rt1        |¬«       t3        |j'                  dd«      ||
j4                  ¬«      ƒ d{  –—†  t7        ||j'                  dd«      |j'                  d«      |
j                  ¬«       i |¥d|i¥}|€t9        d«      ‚|j;                  ||¬«      ƒ d{  –—† }t=        t?        |«      ||¬«      ƒ d{  –—†  tA        |t?        |«      ||
¬«      ƒ d{  –—†  |jB                  �yddl m"} dt?        |«      › �}|jF                  jI                  ||jB                  d¬ «       |jJ                  �1	 |jJ                  jM                  ||jB                  d¬ «      ƒ d{  –—†  tS        jT                  tW        jX                  ||
|||¬"«      «       |€t%        d#«      ‚d$|i|d%   ¥S 7 �Œ—7 �Œl7 �ŒF7 �ŒÚ7 �Œ€7 �Œ7 Œþ7 Œà7 Œ]# t8        $ r!}tO        jP                  d!||«       Y d}~Œ€d}~ww xY w# t8        $ rÏ}tO        jZ                  d&|«       t]        |t        «      rPt_        ta        |d'd(|› d)�«      tb        jd                  ta        |d*d+«      ta        |d,t(        jf                  «      ¬-«      ‚t]        |t^        «      r|‚t_        d.ti        |«      z   tb        jd                  ta        |d*d+«      t(        jf                  ¬-«      ‚d}~ww xY w­w)/a  
    Update an existing API key's parameters.

    Parameters:
    - key: Optional[str] - The key to update. Either key or key_alias must be provided.
    - key_alias: Optional[str] - User-friendly key alias. If key is omitted, also identifies the key to update (must match exactly one key, same as /key/delete's key_aliases)
    - user_id: Optional[str] - User ID associated with key
    - team_id: Optional[str] - Team ID associated with key
    - agent_id: Optional[str] - The agent id associated with the key.
    - organization_id: Optional[str] - The organization id of the key.
    - budget_id: Optional[str] - The budget id associated with the key. Created by calling `/budget/new`.
    - models: Optional[list] - Model_name's a user is allowed to call
    - tags: Optional[List[str]] - Tags for organizing keys (Enterprise only)
    - prompts: Optional[List[str]] - List of prompts that the key is allowed to use.
    - enforced_params: Optional[List[str]] - List of enforced params for the key (Enterprise only). [Docs](https://docs.litellm.ai/docs/proxy/enterprise#enforce-required-params-for-llm-requests)
    - spend: Optional[float] - Amount spent by key
    - max_budget: Optional[float] - Max budget for key
    - model_max_budget: Optional[Dict[str, BudgetConfig]] - Model-specific budgets {"gpt-4": {"budget_limit": 0.0005, "time_period": "30d"}}
    - budget_fallbacks: Optional[Dict[str, List[str]]] - Per-model fallback chain tried in order when that model's own `model_max_budget` is exceeded, e.g. {"gpt-4o": ["gpt-4o-mini"]}.
    - budget_duration: Optional[str] - Budget reset period ("30d", "1h", etc.)
    - soft_budget: Optional[float] - [TODO] Soft budget limit (warning vs. hard stop). Will trigger a slack alert when this soft budget is reached.
    - max_parallel_requests: Optional[int] - Rate limit for parallel requests
    - metadata: Optional[dict] - Metadata for key. Example {"team": "core-infra", "app": "app2"}
    - tpm_limit: Optional[int] - Tokens per minute limit
    - rpm_limit: Optional[int] - Requests per minute limit
    - model_rpm_limit: Optional[dict] - Model-specific RPM limits {"gpt-4": 100, "claude-v1": 200}
    - mcp_rpm_limit: Optional[dict] - Per-MCP-server RPM limits, keyed by MCP server name {"github": 100, "slack": 200}
    - tag_rpm_limit: Optional[dict] - Per-request-tag RPM limits, keyed by request tag {"cell-1": 1000, "cell-2": 500}. Each tag gets an independent counter; absent tags fall back to the key-level rpm limit.
    - model_tpm_limit: Optional[dict] - Model-specific TPM limits {"gpt-4": 100000, "claude-v1": 200000}
    - default_estimated_output_tokens: Optional[int] - Proxy admin only. Expected output tokens reserved for TPM limiting when a request omits max_tokens. Positive integer.
    - default_estimated_output_tokens_per_model: Optional[dict] - Proxy admin only. Per-model override of the above {"gpt-4": 4096, "gpt-3.5-turbo": 1024}
    - tpm_limit_type: Optional[str] - TPM rate limit type - "best_effort_throughput", "guaranteed_throughput", or "dynamic"
    - rpm_limit_type: Optional[str] - RPM rate limit type - "best_effort_throughput", "guaranteed_throughput", or "dynamic"
    - allowed_cache_controls: Optional[list] - List of allowed cache control values
    - duration: Optional[str] - Key validity duration ("30d", "1h", etc.), null to never expire, or "-1" to never expire (deprecated, use null)
    - permissions: Optional[dict] - Key-specific permissions
    - send_invite_email: Optional[bool] - Send invite email to user_id
    - guardrails: Optional[List[str]] - List of active guardrails for the key
    - policies: Optional[List[str]] - List of policy names to apply to the key. Policies define guardrails, conditions, and inheritance rules.
    - disable_global_guardrails: Optional[bool] - Whether to disable global guardrails for the key.
    - throttle_on_budget_exceeded: Optional[bool] - When the key exceeds its max_budget, throttle its tpm/rpm to the global budget_exceeded_throttle_percentage instead of blocking the key entirely.
    - enable_prompt_caching: Optional[bool] - Auto-inject prompt caching breakpoints (Anthropic cache_control markers) on requests made with this key. Anthropic and Bedrock Claude models only.
    - prompts: Optional[List[str]] - List of prompts that the key is allowed to use.
    - blocked: Optional[bool] - Whether the key is blocked
    - aliases: Optional[dict] - Model aliases for the key - [Docs](https://litellm.vercel.app/docs/proxy/virtual_keys#model-aliases)
    - config: Optional[dict] - [DEPRECATED PARAM] Key-specific config.
    - temp_budget_increase: Optional[float] - Temporary budget increase for the key (Enterprise only).
    - temp_budget_expiry: Optional[str] - Expiry time for the temporary budget increase (Enterprise only).
    - allowed_routes: Optional[list] - List of allowed routes for the key. Store the actual route or store a wildcard pattern for a set of routes. Example - ["/chat/completions", "/embeddings", "/keys/*"]
    - allowed_passthrough_routes: Optional[list] - List of allowed pass through routes for the key. Store the actual route or store a wildcard pattern for a set of routes. Example - ["/my-custom-endpoint"]. Use this instead of allowed_routes, if you just want to specify which pass through routes the key can access, without specifying the routes. If allowed_routes is specified, allowed_passthrough_routes is ignored.
    - prompts: Optional[List[str]] - List of allowed prompts for the key. If specified, the key will only be able to use these specific prompts.
    - object_permission: Optional[LiteLLM_ObjectPermissionBase] - key-specific object permission. Example - {"vector_stores": ["vector_store_1", "vector_store_2"], "agents": ["agent_1", "agent_2"], "agent_access_groups": ["dev_group"]}. IF null or {} then no object permission.
    - auto_rotate: Optional[bool] - Whether this key should be automatically rotated
    - rotation_interval: Optional[str] - How often to rotate this key (e.g., '30d', '90d'). Required if auto_rotate=True
    - allowed_vector_store_indexes: Optional[List[dict]] - List of allowed vector store indexes for the key. Example - [{"index_name": "my-index", "index_permissions": ["write", "read"]}]. If specified, the key will only be able to use these specific vector store indexes. Create index, using `/v1/indexes` endpoint.
    - router_settings: Optional[UpdateRouterConfig] - key-specific router settings. Example - {"model_group_retry_policy": {"gpt-4": {"RateLimitErrorRetries": 5}}}. IF null or {} then no router settings.
    - access_group_ids: Optional[List[str]] - List of access group IDs to associate with the key. Access groups define which models a key can access. Example - ["access_group_1", "access_group_2"].
    - budget_limits: Optional[list] - List of concurrent budget windows for the key. Each window specifies a budget_limit, time_period, and optional budget_duration. Example - [{"budget_limit": 10.0, "time_period": "1d"}, {"budget_limit": 50.0, "time_period": "7d"}].

    Example:
    ```bash
    curl --location 'http://0.0.0.0:4000/key/update'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "key": "sk-1234",
        "key_alias": "my-key",
        "user_id": "user-1234",
        "team_id": "team-1234",
        "max_budget": 100,
        "metadata": {"any_key": "any-val"},
    }'
    ```
    r   )r  r  r¥   r~  rž  r  NrÓ   rµ   r+  r¶   )rÅ  r¥   rÒ   rj  )rž   r4  rá   r  r  r¥   rž  r‚  r-  TrÕ   r.  Fr‚  rÒ   r—  )rÒ   r¥   Úexisting_key_tokenrÏ   rÇ   )rÐ   rÅ  úNot connected to DB!rˆ  r‰  rŠ  )Úspend_counter_cacheú
spend:key:é<   ©rt  ræ   ÚttlzFailed to update spend counter %s in Redis after key spend update: %s. Budget checks may use stale value until counter expires.rŒ  r�  rt  rž   zBlitellm.proxy.proxy_server.update_key_fn(): Exception occured - %sr¸   zAuthentication Error(ú)r×   ÚNoner·   rÔ   úAuthentication Error, )5r©  r  r  r¥   r~  rž  r  rR  rP  rQ  r   rz  rt  rÒ   r|  r°  r;  r<  rµ  r¹   r   r  rx  re  r»  r¼  rÅ  rà   r!  r‘  r+   rY   rK   r¢  rµ  Úin_memory_cacheÚ	set_cacheÚredis_cacheÚasync_set_cacher   rº   rÆ  rÇ  r>   r’  r?  r¸  rÝ   r8  rÞ   Ú
auth_errorrw  r’   )r±  rž   rá   ry  r  r  r¥   r~  rž  r  r4  rt  Úcustom_key_update_hookrA  r-  rÕ   rF  Únew_key_aliasr”  r¨  rµ  Úcounter_keyÚ	redis_errr#  s                           r€   Úupdate_key_fnrÆ  £
  sd  è ø€ ÷j÷ ðC
à�?‰?Ð&´·±¸d¿o¹oÔ0NÐRV×RaÑRaÐdeÒReÜØØÐ#^Ð_c×_nÑ_nÐ^oÐ!pÐqôð ô )GØ—(‘(Ø'Ø—n‘nô)
÷ #
Ðô
 .°4ÐJZÔ[ˆØˆŒä'ØØ-Ø/Ø!Ø%Ø'Ø1ô
÷ 	
ð 	
ð `vÐØ!Ð-Ü×*Ñ*Ð+AÔBÙ&<¸TÓ&B× B‘ä Ð!MÓNÐNØ$Ÿj™j¨°TÓ:ˆHØ#ŸZ™Z¨	Ð3]Ó^ˆGÙÜ#´×0IÑ0IÐRYÔZÐZô 	' t¸5ÕAÜ*AÀtÐ^nÔ*o×$oÐð  2×5Ñ5°kÀ4ÓHˆØÐ,×6Ñ6Ò6Ü&°Õ?ä'Ø(×,Ñ,¨[¸$Ó?Ø'Ø/×5Ñ5ô
÷ 	
ð 	
ô 	!ØØ×"Ñ" =°%Ó8Ø×"Ñ"Ð#6Ó7Ø/×9Ñ9õ		
ð <Ð,Ð;¨g°sÑ;ˆØÐ ÜÐ2Ó3Ð3Ø -× 9Ñ 9ÀÈ%Ð 9Ó P×Pˆô 'Ü.¨sÓ3Ø1Ø/ô
÷ 	
ð 	
ô 6Ø'Ü+¨CÓ0ØØ-ô	
÷ 	
ð 	
ð �:‰:Ð!ÝFà#-Ô.CÀCÓ.HÐ-IÐ!JˆKØ×/Ñ/×9Ñ9¸kÐQU×Q[ÑQ[ÐacÐ9ÔdØ"×.Ñ.Ð:ðØ-×9Ñ9×IÑIÈkÐae×akÑakÐqsÐIÓt×tÐtô 	×ÑÜ#×:Ñ:ØØ!1Ø!Ø"3Ø#5ôô	
ð ÐÜÐGÓHÐHà�sÐ/˜h vÑ.Ð/Ð/ðQ#
ùð	
ùð !Cùð %pùð	
ùð" Qùð	
øð	
øð uùÜ ò Ü(×0Ñ0ðSà#Ø!÷	ñ ûðûô. ò 
Ü×&Ñ&Ð'kÐmnÔoÜ�aœÔ'Ü Ü  8Ð/DÀQÀCÀqÐ-IÓJÜ$×/Ñ/Ü˜a ¨&Ó1Ü˜Q ¬v×/JÑ/JÓKô	ð ô ˜œ>Ô*ØˆGÜØ,¬s°1«vÑ5Ü ×+Ñ+Ü˜!˜W fÓ-Ü×,Ñ,ô	
ð 	
ûð
üsû   ‚Q”A;M+ ÂL&Â-M+ Â=L)Â>(M+ Ã&L,Ã'A.M+ ÅL/ÅAM+ Æ2L2Æ3A'M+ ÈL5ÈM+ È9L8È:M+ ÉL:ÉAM+ Ê3+L> ËL<ËL> Ë#AM+ Ì%QÌ&M+ Ì)M+ Ì,M+ Ì/M+ Ì2M+ Ì5M+ Ì8M+ Ì:M+ Ì<L> Ì>	M(ÍM#ÍM+ Í#M(Í(M+ Í+	QÍ4C
P>Ð>QÑQz/key/bulk_updatec              ƒ   ó²  K  — ddl m}m}m}m}m} |j                  t        j                  j                  k7  rt        dddi¬«      ‚|€t        ddd	i¬«      ‚| j                  st        d
ddi¬«      ‚d}t        | j                  «      |kD  r)t        d
dd|› dt        | j                  «      › d�i¬«      ‚g }	g }
| j                  D ]†  }	 t        |j                  |j                  |j                   |j"                  |j$                  ¬«      }t'        ||||||||¬«      ƒ d{  –—† }|	j)                  t+        |j                  |¬«      «       Œˆ tK        t        | j                  «      |	|
¬«      S 7 ŒM# t,        $ �rX}t/        j0                  d|j                  |«       t3        |t        «      rD|j4                  }t3        |t6        «      r|j9                  dt;        |«      «      }n4t;        |«      }n(t3        |t<        «      r|j>                  }nt;        |«      }d}	 |jA                  |j                  dd¬«      ƒ d{  –—†7  }|�MtC        |d«      r|jE                  «       }ntC        |d«      r|j7                  «       }|r|jG                  dd«       n# t,        $ r Y nw xY w|
j)                  tI        |j                  ||¬«      «       Y d}~�Œ	d}~ww xY w­w)aê  
    Bulk update multiple keys at once.
    
    This endpoint allows updating multiple keys in a single request. Each key update
    is processed independently - if some updates fail, others will still succeed.
    
    Parameters:
    - keys: List[BulkUpdateKeyRequestItem] - List of key update requests, each containing:
        - key: str - The key identifier (token) to update
        - budget_id: Optional[str] - Budget ID associated with the key
        - max_budget: Optional[float] - Max budget for key
        - team_id: Optional[str] - Team ID associated with key
        - tags: Optional[List[str]] - Tags for organizing keys
    
    Returns:
    - total_requested: int - Total number of keys requested for update
    - successful_updates: List[SuccessfulKeyUpdate] - List of successfully updated keys with their updated info
    - failed_updates: List[FailedKeyUpdate] - List of failed updates with key_info and failed_reason
    
    Example request:
    ```bash
    curl --location 'http://0.0.0.0:4000/key/bulk_update'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "keys": [
            {
                "key": "sk-1234",
                "max_budget": 100.0,
                "team_id": "team-123",
                "tags": ["production", "api"]
            },
            {
                "key": "sk-5678",
                "budget_id": "budget-456",
                "tags": ["staging"]
            }
        ]
    }'
    ```
    r   ©r  r¥   r~  rž  r  r´   rµ   z.Only proxy admins can perform bulk key updatesr¶   Nr  ro  rÓ   zNo keys provided for updateúMaximum ú$ keys can be updated at once. Found z keys.)rt  rŠ  rR  r¿   r’  )r}  rá   ry  r¥   rž  r~  r  r  ©rt  Úkey_infozFailed to update key %s: %srt  ra  ©rÅ  r§  Ú
query_typer‰   rŒ   rÅ  ©rt  rÌ  Úfailed_reason©Útotal_requestedÚsuccessful_updatesÚfailed_updates)&r©  r  r¥   r~  rž  r  rã   rä   rå   ræ   r   rÜ  r¾  r  rt  rŠ  rR  r¿   r’  r–  r\  ro   r!  r   r?  r¸  r¸   rŒ   r¹   r’   rÝ   rÕ   Úget_datar“  r‰   r-  rn   rl   )rž   rá   ry  r  r¥   r~  rž  r  ÚMAX_BATCH_SIZErÓ  rÔ  Úkey_update_itemr}  r•  r#  Úerror_detailÚerror_messagerÌ  r4  s                      r€   Úbulk_update_keysrÚ  ‡  sõ  è ø€ ÷põ ð ×"Ñ"Ô&6×&BÑ&B×&HÑ&HÒHÜØØÐMÐNô
ð 	
ð
 ÐÜØØÐ5Ð6ô
ð 	
ð
 �9Š9ÜØØÐ:Ð;ô
ð 	
ð
  €NÜ
ˆ4�9‰9ƒ~˜Ò&ÜØØ˜x¨Ð'7Ð7[Ô\_Ð`d×`iÑ`iÓ\jÐ[kÐkqÐrÐsô
ð 	
ð
 <>ÐØ35€NàŸ9™9ò @ˆð?	Ü!1Ø#×'Ñ'Ø)×3Ñ3Ø*×5Ñ5Ø'×/Ñ/Ø$×)Ñ)ô"Ðô &@Ø#5Ø"3Ø#5Ø+Ø#5Ø"3Ø%Ø'=ô	&÷ 	 Ðð ×%Ñ%Ü#Ø'×+Ñ+Ø-ôõð)@ôD !Ü˜DŸI™I›Ø-Ø%ôð ðs	 ùô$ ó %	Ü ×*Ñ*Ð+HÈ/×J]ÑJ]Ð_`Ôaä˜!œ]Ô+Ø Ÿx™x�Ü˜l¬DÔ1Ø$0×$4Ñ$4°W¼cÀ!»fÓ$E‘Mä$'¨Ó$5‘MÜ˜Aœ~Ô.Ø !§	¡	‘ä # A£�àˆHðØ)6×)?Ñ)?Ø)×-Ñ-Ø$Ø,ð *@ó *÷ $ð $Ð ð
 $Ð/ÜÐ/°Ô>Ø#3×#>Ñ#>Ó#@™Ü Ð!1°6Ô:Ø#3×#8Ñ#8Ó#:˜ÙØ Ÿ™ W¨dÔ3ùÜò Ùðúð ×!Ñ!ÜØ'×+Ñ+Ø%Ø"/ô÷ò ûð?%	üsu   ‚CKÃ
AE2Ä"E0Ä#*E2Å#KÅ0E2Å2
KÅ<BKÈ!JÈ=I È>AJÊKÊ	JÊKÊJÊ*KË	KËKËKr?  c                 ó¸  — t        |t        «      rD|j                  }t        |t        «      r|j	                  dt        |«      «      }n4t        |«      }n(t        |t        «      r|j                  }nt        |«      }d}|�Mt        |d«      r|j                  «       }nt        |d«      r|j                  «       }|r|j                  dd«       t        | ||¬«      S )zKNormalize an exception from the per-key update loop into a FailedKeyUpdate.rµ   Nr‰   rŒ   rÅ  rÏ  )r¸  r   r¸   rŒ   r¹   r’   rÝ   rÕ   r“  r‰   r-  rn   )rÅ  r?  r4  r¸   rÙ  rÌ  s         r€   Ú_build_failed_team_key_updaterÜ  ,  s»   € ô �)œ]Ô+Ø!×(Ñ(ˆÜ�fœdÔ#Ø"ŸJ™J w´°I³Ó?‰Mä ›K‰MÜ	�Iœ~Ô	.Ø!×)Ñ)‰ä˜I›ˆà)-€HØÐ#ÜÐ# \Ô2Ø'×2Ñ2Ó4‰HÜÐ% vÔ.Ø'×,Ñ,Ó.ˆHÙØ�L‰L˜ $Ô'ä˜u¨xÀ}ÔUÐUr‚   z/team/key/bulk_updatec              ƒ   ó„  K  — ddl m}m}m}m}m} |€t        dddi¬«      ‚| j                  st        ddd	i¬«      ‚d}| j                  �At        | j                  «      |kD  r)t        ddd
|› dt        | j                  «      › d�i¬«      ‚| j                  rÍt        j                  t        j                  «      }	t        t!        |«      «      j#                  | j                  dddiddigidddidd|	iigigdœddi|dz   ¬«      ƒ d{  –—† }
t        |
«      |kD  r#t        ddd| j                  › d|› d|› d�i¬«      ‚t%        d|
D �cg c]  }|j&                  ‘Œ c}«      }nÐ| j                  �t        | j                  «      dk(  rt        dddi¬«      ‚g }g }t)        «       }| j                  D ]E  }t+        |«      }||v rŒ|j-                  |«       |j/                  |«       |j/                  |«       ŒG t        t!        |«      «      j#                  | j                  d|idœ¬«      ƒ d{  –—† }
|j0                  t2        j4                  j6                  k7  rO|
r|
d   nt9        d | j                  g ¬!«      }t;        j<                  |t>        j@                  |||¬"«      ƒ d{  –—†  tC        | jD                  |¬#«       |st        d$dd%| j                  › �i¬«      ‚|
D �ci c]  }|j&                  |“Œ }}| jD                  jG                  d&¬'«      }g }g }|D ]�  }t+        |«      }	 ||vrt        d$dd(| j                  › �i¬«      ‚tH        jK                  || j                  d)œ|¥«      }tM        ||||||||||   ¬*«	      ƒ d{  –—† }|j/                  tO        ||¬+«      «       Œ� t[        t        |«      ||¬/«      S 7 �Œ¹c c}w 7 �Œ›7 �Œ(c c}w 7 ŒL# tP        $ r\}tS        jT                  d,|dd- | j                  |«       |j/                  tW        |||jY                  |«      ¬.«      «       Y d}~�Œd}~ww xY w­w)0at  
    Apply one update payload to many keys inside a single team.

    Pass `team_id` plus either `key_ids` or `all_keys_in_team=True`. The
    `update_fields` payload is broadcast to every selected key. Per-key
    failures are returned in `failed_updates` rather than aborting the batch.

    Callable by proxy admins, or by team admins with `KEY_UPDATE` permission.
    r   rÈ  Nr  rµ   ro  r¶   rÓ   zteam_id is requiredrÉ  rÊ  z	 key_ids.ÚORÚblockedFrV  Úgt)r¿   ÚANDrÅ  Úascrt  )r�   Úorderrs  zTeam z has more than z- keys. Use `key_ids` to update in batches of ú.z	list[str]z7key_ids must be provided when all_keys_in_team is FalseÚin)r¿   rÅ  r`  Ú__team_scope_auth_check__)rÅ  r¿   ru   r�  rƒ  r  zNo keys found for team Trú   zKey not found in team )rt  r¿   )	r}  rá   ry  r¥   rž  r~  r  r  r4  rË  z)Failed to update key %s... in team %s: %sé   )rÅ  r?  r4  rÑ  ).r©  r  r¥   r~  rž  r  r   r¿   Úkey_idsr¾  Úall_keys_in_teamr   rË   r	   rÌ   r¤   rg   r›   r   rÅ  r9  rY   Úaddr\  rã   rä   rå   ræ   r)   rS   rŽ  r=  r�  r@   Úupdate_fieldsr‰   r  rÃ  r–  ro   r!  r   r?  rÜ  r¹   rl   )rž   rá   ry  r  r¥   r~  rž  r  rÖ  rË   Úexisting_keysÚrowÚrequested_tokensÚhashed_key_idsÚseen_hashesrP  ÚhÚauth_anchorÚexisting_by_tokenÚupdate_field_dictrÓ  rÔ  rÅ  Údb_tokenr}  r•  r#  s                              r€   Úbulk_update_team_keysrö  I  sî  è ø€ ÷0õ ð ÐÜØØÐ5Ð6ô
ð 	
ð
 �<Š<ÜØØÐ2Ð3ô
ð 	
ð
  €NØ‡|�|Ð¤C¨¯©Ó$5¸Ò$FÜØà˜8 NÐ#3Ð3WÔX[Ð\`×\hÑ\hÓXiÐWjÐjsÐtðô
ð 	
ð ×Òô —\‘\¤(§,¡,Ó/ˆÜ+Ô,GÈÓ,VÓW×aÑaàŸ<™<à˜Y¨Ð.°¸DÐ0AÐBÐCØ˜Y¨Ð-°	¸DÀ#¸;Ð/GÐHÐIðñð ˜EÐ"Ø !Ñ#ð bó 

÷ 

ˆô ˆ}Ó Ò.ÜØà˜u T§\¡\ N°/À.ÐAQÐQ~ð  @Nð  Oð  OPð  Qðôð ô  Ø¨}Ö=¨˜#Ÿ)›)Ò=ó
Ñð �<‰<Ð¤3 t§|¡|Ó#4¸Ò#9ÜØØÐ!ZÐ[ôð ð
 ÐØ "ˆÜ ›UˆØ—‘ò 	%ˆAÜ% aÓ(ˆAØ�KÑØØ�O‰O˜AÔØ×#Ñ# AÔ&Ø×!Ñ! !Õ$ð	%ô ,Ô,GÈÓ,VÓW×aÑaØ"Ÿl™l°d¸NÐ5KÑLð bó 
÷ 
ˆð
 ×"Ñ"Ô&6×&BÑ&B×&HÑ&HÒHñ ð ˜!Òä*Ø1ØŸ™Øôð 	ô )×XÑXØ/Ü%×0Ñ0Ø'Ø(Ø1ô
÷ 	
ð 	
ô 0°T×5GÑ5GÐ[lÕmáÜØØÐ6°t·|±|°nÐEÐFô
ð 	
ð
 ;HÖH°3 §	¡	¨3¡ÐHÐÐHØ#×1Ñ1×<Ñ<È4Ð<ÓPÐà;=ÐØ35€Nà!ò (ˆÜ(¨Ó/ˆð&	ØÐ0Ñ0Ü#Ø #Ø#Ð'=¸d¿l¹l¸^Ð%LÐMôð ô "2×!@Ñ!@à Ø#Ÿ|™|ñð (ðó"Ðô &@Ø#5Ø"3Ø#5Ø+Ø#5Ø"3Ø%Ø'=Ø!2°8Ñ!<ô
&÷ 
 Ðð ×%Ñ%Ô&9¸eÐN^Ô&_Õ`ð;(ôT !ÜÐ,Ó-Ø-Ø%ôð ðo

ûò& >ð&
ùð	
ûò$  Ið.
 ùô ò 		ä ×*Ñ*Ð+VÐX`ÐadÐbdÐXeÐgk×gsÑgsÐuvÔwØ×!Ñ!Ü-ØØØ%6×%:Ñ%:¸8Ó%Dô÷ò ûð		üs”   ‚DQ Ä
OÄ?Q Å
O
ÅCQ È0OÈ1A5Q Ê&OÊ'=Q Ë$OË82Q Ì+AOÎ	OÎ
 OÎ*Q ÏQ ÏQ ÏQ ÏOÏ	P=Ï!AP8Ð2Q Ð8P=Ð=Q rt  rb  r‡  c           
   ƒ   óN  K  — t        | j                  «      dkD  rE| j                  D ]6  }|t        j                  j                  k(  rŒ!t        |||¬«      ƒ d{  –—†  Œ8 | j                  �À|j                  rN| j                  |j                  kD  r5t        dd| j                  › d| j                  › d|j                  › d�¬	«      ‚|j                  rZ| j                  rN| j                  |j                  kD  r5t        dd| j                  › d
| j                  › d|j                  › d�¬	«      ‚t        t        t        |«      | j                  ¬«      }| j                  �*|s(t        dd| j                  › d|j                  › d�¬	«      ‚|j                  t         j"                  j                  k(  sKt%        ||¬«      s>t'        j(                  |t        t        |«      t*        j,                  j                  ¬«      ryt        dd|j                  › d|j                  › d�¬	«      ‚7 �ŒÉ­w)a<  
    Validate that a key can be moved to a new team.

    - The team must have access to the key's models
    - The key's user_id must be a member of the team
    - The key's tpm/rpm limit must be less than the team's tpm/rpm limit
    - The person initiating the change must be either Proxy Admin or Team Admin
    r   )rî  Úteam_objectr  Nr´   zKey=z has a tpm_limit=z, which is greater than the team's tpm_limit=rä  r¶   z has a rpm_limit=z, which is greater than the team's rpm_limit=rî   rï   z is not a member of the team=z&. Check team members via `/team/info`.©rá   r”  rñ   z- is not a Proxy Admin or Team Admin for team=z\. Please ask your Proxy Admin to allow this action under 'Member Permissions' for this team.)r¾  ru   ÚSpecialModelNamesÚall_team_modelsræ   r,   rf  r   rÅ  rg  rÆ   r   r—  r�   r¿   rã   rä   rå   rB   rS   rô   r=  r�  )rt  rb  r‡  r  rî  Úmember_objects         r€   r�  r�    s1  è ø€ ô ˆ3�:‰:ƒ˜ÒØ—Z‘Zò 		ˆEð Ô)×9Ñ9×?Ñ?Ò?ØÜ'ØØ Ø%ô÷ ñ ð		ð ‡}�}Ð Ø�>Š>˜cŸm™m¨d¯n©nÒ<ÜØØ˜cŸi™i˜[Ð(9¸#¿-¹-¸ÐHtÐuy÷  vDñ  vDð  uEð  EFð  Gôð ð �>Š>˜cŸmšm°·±ÀÇÁÒ0NÜØØ˜cŸi™i˜[Ð(9¸#¿-¹-¸ÐHtÐuy÷  vDñ  vDð  uEð  EFð  Gôð ô -¼Ô=WÐY]Ó8^Ðhk×hsÑhsÔt€MØ
‡{�{ÐÙÜØØ˜sŸ{™{˜mÐ+HÈÏÉÈÐV|Ð}ôð ð 	×%Ñ%Ô)9×)EÑ)E×)KÑ)KÒKÜØ1Øõ
ô &×TÑTØ,ÜÔ6¸Ó=Ü%×0Ñ0×6Ñ6õ
ð 	äØØÐ.×6Ñ6Ð7Ð7dÐei×eqÑeqÐdrð  sOð  Pô
ð 	
ðWûs   ‚AH%ÁH"ÁG	H%z/key/deletec           	   ƒ   ó  K  — 	 ddl m}m} |€t        d«      ‚|�t	        |t
        «      sd}t        j                  d|j                  «       d}g }| j                  rFt        | j                  |||¬«      ƒ d{  –—† \  }}t        | j                  «      }| j                  }n^| j                  rGt        | j                  ||||¬«      ƒ d{  –—† \  }}t        | j                  «      }| j                  }nt        d«      ‚|€+t        d	t         j"                  d
t$        j&                  ¬«      ‚t        j                  d|«       	 |t        |«      k(  sJ ‚	 t        j                  d|j*                  j,                  «       t/        j0                  t3        j4                  | ||||¬«      «       d|iS 7 �Œ87 Œç# t        $ r t)        ddd|› d|› �i¬«      ‚w xY w# t        $ r&}	t        j6                  d|	«       t9        |	«      ‚d}	~	ww xY w­w)aŽ  
    Delete a key from the key management system.

    Parameters::
    - keys (List[str]): A list of keys or hashed keys to delete. Example {"keys": ["sk-QWrxEynunsNpV1zT48HIrw", "837e17519f44683334df5291321d97b8bf1098cd490e49e215f6fea935aa28be"]}
    - key_aliases (List[str]): A list of key aliases to delete. Can be passed instead of `keys`.Example {"key_aliases": ["alias1", "alias2"]}

    Returns:
    - deleted_keys (List[str]): A list of deleted keys. Example {"deleted_keys": ["sk-QWrxEynunsNpV1zT48HIrw", "837e17519f44683334df5291321d97b8bf1098cd490e49e215f6fea935aa28be"]}

    Example:
    ```bash
    curl --location 'http://0.0.0.0:4000/key/delete'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "keys": ["sk-QWrxEynunsNpV1zT48HIrw"]
    }'
    ```

    Raises:
        HTTPException: If an error occurs during key deletion.
    r   r�  Nr´  zuser_api_key_dict.user_role: %s©Útokensrž  rá   ry  )Úkey_aliasesr¥   rž  rá   ry  zInvalid request typezFFailed to delete keys got None response from delete_verification_tokenrÜ  rÔ   z/key/delete - deleted_keys=%srÓ   rµ   z€Not all keys passed in were deleted. This probably means you don't have access to delete all the keys passed in. Keys passed in=z, Deleted keys =r¶   z%/keys/delete - cache after delete: %s)rž   Úkeys_being_deletedrá   ry  r¨  Údeleted_keyszBlitellm.proxy.proxy_server.delete_key_fn(): Exception occured - %s)r©  r¥   rž  r!  r¸  r’   r   r­  rã   rÜ  Údelete_verification_tokensr¾  r   Údelete_key_aliasesrµ  rÝ   rÞ   Úinternal_server_errorr   r9  r   r½  Ú
cache_dictrÆ  rÇ  r>   Úasync_key_deleted_hookr?  rZ   )
rž   rá   ry  r¥   rž  Únum_keys_to_be_deletedr  Únumber_deleted_keysÚ_keys_being_deletedr#  s
             r€   Údelete_key_fnr  G  sH  è ø€ ðBI+ßPàÐ ÜÐ2Ó3Ð3ð Ð)´*Ð=OÔQTÔ2UØ!%Ðô 	×"Ñ"Ð#DÐFW×FaÑFaÔbà!"ÐØˆØ�9Š9Ü=WØ—y‘yØ#5Ø"3Ø#5ô	>÷ 8Ñ4ÐÐ!4ô &)¨¯©£^Ð"ØŸ9™9‰LØ×ÒÜ=OØ ×,Ñ,Ø+Ø#5Ø"3Ø#5ô>÷ 8Ñ4ÐÐ!4ô &)¨×)9Ñ)9Ó%:Ð"Ø×+Ñ+‰LäÐ3Ó4Ð4àÐ&Ü Ø`Ü$×:Ñ:ØÜ×:Ñ:ô	ð ô 	×"Ñ"Ð#BÐDWÔXð	Ø)¬S°Ó->Ò>Ð>Ñ>ô 	×"Ñ"Ø3Ð5G×5WÑ5W×5bÑ5bô	
ô 	×ÑÜ#×:Ñ:ØØ#6Ø"3Ø#5Ø,ôô	
ð  Ð-Ð-ðm8ùð8ùô. ò 	ÜØàð   `ð  awð  `xð  xHð  I\ð  H]ð  ^ðôð ð	ûô. ò +Ü×&Ñ&Ð'kÐmnÔoÜ'¨Ó*Ð*ûð+üsh   ‚H
„A5G Á9F1Á:AG ÃF4ÃA7G ÅF6 ÅAG Æ0H
Æ1G Æ4G Æ6GÇG Ç	HÇ!!HÈHÈH
Úapi_key_hashr…  c              ƒ   óX   K  — t        t        j                  | ||¬«      ƒ d {  –—† S 7 Œ­w)N)rá  Ú	entity_idr…  Úcache)r?   r(   ÚKEY©r  r…  rž  s      r€   Ú_build_model_max_budget_usager  ´  s1   è ø€ ô
 .Ü&×*Ñ*ØØ)Ø ô	÷ ð ð ús   ‚!*£(¤*z/v2/key/info)r’  r"  Úinclude_in_schemac              ƒ   ó”  K  — ddl m}m} 	 |€t        d«      ‚| €t	        t
        j                  ddi¬«      ‚| j                  rt        | j                  «      ng }| j                  rtt        t        |«      «      j                  dd	| j                  iid
di¬«      ƒ d{  –—† }|D �cg c]  }|j                  sŒ|j                  ‘Œ }}|j                  |«       |s| j                  g dœS |j                  |dd¬«      ƒ d{  –—† }|s| j                  g dœS g }	|D ]Ï  }
t!        ||
j                  |
¬«      ƒ d{  –—† sŒ$	 |
j#                  «       }|j'                  dd«      }|j)                  d«      xs i }|j)                  d
«      xs i }|s%t+        |t$        «      r|j)                  d«      xs i }|r%|r#t-        |||j.                  ¬«      ƒ d{  –—† |d<   |	j1                  |«       ŒÑ | j                  |	dœS 7 �Œ_c c}w 7 �Œ7 ŒÍ# t        $ r |
j%                  «       }Y ŒÔw xY w7 ŒU# t        $ r}t3        |«      ‚d}~ww xY w­w)a  
    Retrieve information about a list of keys.

    **New endpoint**. Currently admin only.
    Parameters:
        keys: Optional[list] = body parameter representing the key(s) in the request
        user_api_key_dict: UserAPIKeyAuth = Dependency representing the user's API key
    Returns:
        Dict containing the key and its associated information

    Example Curl:
    ```
    curl -X GET "http://0.0.0.0:4000/key/info"     -H "Authorization: Bearer sk-1234"     -d {"keys": ["sk-1", "sk-2", "sk-3"]}
    ```
    r   ©Úmodel_max_budget_limiterr¥   Nú�Database not connected. Connect a database to your proxy - https://docs.litellm.ai/docs/simple_proxy#managing-auth---virtual-keysrÕ   z%Malformed request. No keys passed in.r¶   rÒ   rå  r  Tr  ©rt  Úinfort  Úfind_allrÍ  ©rá   rt  rÌ  rÅ  r…  r  Úmodel_max_budget_usage)r©  r  r¥   r!  r   r   ÚHTTP_422_UNPROCESSABLE_ENTITYrÜ  Úlistr   r¤   rg   r›   rÅ  ÚextendrÕ  Ú_can_user_query_key_infor‰   rŒ   r-  r¹   r¸  r  Ú
dual_cacher\  rZ   )rž   rá   r  r¥   Útokens_to_queryÚ
alias_rowsrí  Úalias_tokensrÌ  Úfiltered_key_inforP  Úk_dictÚk_token_hashr…  Úbudget_tabler#  s                   r€   Úinfo_key_fn_v2r)  Á  sf  è ø€ ÷6ð
9+ØÐ Üð Tóð ð ˆ<ÜÜ"×@Ñ@Ø!Ð#JÐKôð ð 59·I²I¤ d§i¡i¤À2ˆØ×ÒÜ&3Ô4OÐP]Ó4^Ó&_×&iÑ&iØ" T¨4×+;Ñ+;Ð$<Ð=Ø/°Ð6ð 'jó '÷ !ˆJð 9CÖ"P°ÀcÇiÃi 3§9£9Ð"PˆLÐ"PØ×"Ñ" <Ô0áØŸ9™9¨bÑ1Ð1à -× 6Ñ 6¸_ÐY^ÐkuÐ 6Ó v×vˆÙØŸ9™9¨bÑ1Ð1à#%ÐØò 	-ˆAÜ1Ø"3Ø—G‘GØô÷ ð ð
 ð"ØŸ™›�ð "Ÿ:™: g¨tÓ4ˆLà%Ÿz™zÐ*<Ó=ÒCÀÐØ!Ÿ:™:Ð&<Ó=ÒCÀˆLÙ#¬
°<ÄÔ(FØ#/×#3Ñ#3Ð4FÓ#GÒ#MÈ2Ð Ù¡LÜ9VØ!-Ø%5Ø'?×'JÑ'Jô:÷ 4�Ð/Ñ0ð ×$Ñ$ VÕ,ð1	-ð2 —y‘yÐ*;Ñ<Ð<ðQ!ûò #Qð wùðùô ò "ØŸ™›’ð"úð4ùô ò +Ü'¨Ó*Ð*ûð+üsº   ‚	IŒBH, ÂG>Â H, Â(HÂ:HÃ#H, Ã+IÃ,H, ÄHÄH, ÄIÄ"H, Ä;H	Ä<H, ÅHÅBH, ÇH*Ç(H, Ç=IÇ>H, ÈH, È	H, ÈH'È$H, È&H'È'H, È,	IÈ5I É IÉIz	/key/infozKey in the request parameters)Údefaultr$  c              ƒ   ó   K  — ddl m}m} 	 |€t        d«      ‚| xs |j                  } | }| �t        | ¬«      }t        t        |«      «      j                  d|iddi¬	«      ƒ d{  –—† }|€+t        d
t        j                  dt        j                  ¬«      ‚t        || |¬«      ƒ d{  –—† dur(t        t        j                   d|j"                  › �¬«      ‚	 |j%                  «       }|j)                  d«      }|j+                  d«      xs i }|j+                  d«      xs i }|s%t-        |t&        «      r|j+                  d«      xs i }|r%|r#t/        |||j0                  ¬«      ƒ d{  –—† |d<   t3        ||«      ƒ d{  –—† }| |dœS 7 �Œ%7 Œä# t        $ r |j'                  «       }Y ŒÂw xY w7 ŒD7 Œ/# t        $ r}	t5        |	«      ‚d}	~	ww xY w­w)aù  
    Retrieve information about a key.

    Parameters:
    - key: str | None (query parameter) - The key to look up. Accepts the plaintext key or its hash.
      Defaults to the key in the Authorization header.

    Returns:
    - key: str - The key that was looked up, echoed back as it was passed in
    - info: dict - The key's row, minus the hashed token
        - key_alias: str | None - User-friendly key alias
        - spend: float - Amount spent by the key. When budget_duration is set this covers only the
          current budget window, not the key's lifetime
        - max_budget: float | None - Max budget for the key, enforced against spend
        - budget_duration: str | None - Budget reset period ("30d", "1h", etc.)
        - budget_reset_at: datetime | None - When the current budget window ends and spend is next
          reset to 0, not when it was last reset. Reset times snap to standard boundaries in the
          configured timezone (30d and 1mo land on the 1st of the month, 7d on Monday, 1h on the
          hour), so subtracting budget_duration from it does not give the window's start
        - model_max_budget: dict - Per-model budgets, e.g. {"gpt-4": {"budget_limit": 0.0005, "time_period": "30d"}}
        - model_max_budget_usage: dict | None - Current-window spend per model, present only when
          the key has per-model budgets
        - models: list - Model_name's the key is allowed to call
        - tpm_limit / rpm_limit: int | None - Tokens and requests per minute limits
        - metadata: dict - Metadata for the key, e.g. {"team": "core-infra"}
        - blocked: bool | None - Whether the key is blocked
        - expires: datetime | None - When the key stops authenticating requests
        - last_active: datetime | None - When the key was last used
        - object_permission: dict | None - Resolved vector store / MCP permissions when the key has
          an object_permission_id

    Example Curl:
    ```
    curl -X GET "http://0.0.0.0:4000/key/info?key=sk-test-example-key-123" -H "Authorization: Bearer sk-1234"
    ```

    Example Curl - if no key is passed, it will use the Key Passed in Authorization Header
    ```
    curl -X GET "http://0.0.0.0:4000/key/info" -H "Authorization: Bearer sk-test-example-key-123"
    ```
    r   r  Nr  rp  rÅ  r  Tr  zKey not found in databasert  rÔ   r  ú9You are not allowed to access this key's info. Your role=r¶   r…  r  r  r  )r©  r  r¥   r!  Úapi_keyrY   r¤   rg   ra  rÝ   rÞ   ru  r   rv  r   r   r  rã   r‰   rŒ   r-  r¹   r¸  r  r!  rN   rZ   )
rt  rá   r  r¥   r  rÌ  Úkey_token_hashr…  r(  r#  s
             r€   Úinfo_key_fnr/    s  è ø€ ÷bð
;+ØÐ Üð Tóð ð
 Ò.Ð&×.Ñ.ˆØ!$ˆ
Øˆ?Ü.°SÔ9ˆJÜ&Ô'BÀ=Ó'QÓR×^Ñ^Ø˜JÐ'Ø+¨TÐ2ð _ó 
÷ 
ˆð ÐÜ Ø3Ü$×4Ñ4ØÜ×.Ñ.ô	ð ô +Ø"3ØØ!ô÷ ð
 ñô  Ü"×5Ñ5ØRÐSd×SnÑSnÐRoÐpôð ð
	'Ø×*Ñ*Ó,ˆHð !)§¡¨WÓ 5ˆà#Ÿ<™<Ð(:Ó;ÒA¸rÐØ&Ÿl™lÐ+AÓBÒHÀbˆÙ¤J¨|¼TÔ$BØ+×/Ñ/Ð0BÓCÒIÀrÐÙ¡Ü7TØ+Ø!1Ø#;×#FÑ#Fô8÷ 2ˆHÐ-Ñ.ô :¸(ÀMÓR×Rˆà HÑ-Ð-ð]
ùðùô ò 	'à—}‘}“ŠHð	'úð2øð Sùô ò +Ü'¨Ó*Ð*ûð+üs‘   ‚	GŒAF2 Á%F
Á&AF2 Â(FÂ).F2 ÃF Ã(BF2 Å)F.Å*F2 Æ F0ÆF2 Æ	GÆ
F2 ÆF2 ÆF+Æ(F2 Æ*F+Æ+F2 Æ0F2 Æ2	GÆ;GÇGÇGru   c                 ó¶   — | �|€y| D ]O  }|j                  |¬«      sŒ|rŒt        t        j                  ddt        j
                  j                  › �i¬«      ‚ y)z£
    if is_model_access_group is True + is_wildcard_route is True, check if user is a premium user

    Return True if user is a premium user, False otherwise
    T)Úmodel_access_grouprµ   z`Setting a model access group on a wildcard model is only available for LiteLLM Enterprise users.r¶   )Ú)_is_model_access_group_for_wildcard_router   r   r  r¶  r·  ræ   )ru   r  r  rî  s       r€   r"  r"  ‘  sŽ   € ð €~˜Ð+Øàò ˆØ×?Ñ?ÐSXÐ?ÕYÚÜ#Ü &× 9Ñ 9àð  $Dô  EV÷  Egñ  Eg÷  Emñ  Emð  Dnð  "oðôð ðð r‚   ç        Úinsert_datar¦  )r   rt  rk  ÚaliasesÚconfigr¢  r�  r‘  rŠ  rd  rß  rj  r‡   Úagent_idr„   rã   re  rf  rg  rÎ  )r4  r‘  Úupdate_key_valuesÚallowed_cache_controlsrH  Úbudget_fallbacksrã  rä  Úmcp_rpm_limitÚtag_rpm_limitÚ
guardrailsÚpoliciesÚpromptsÚteamsr§  )rt  r   Úsend_invite_emailrˆ  r‰  r(  Ússo_user_idrh  rZ  r  c8              ƒ   ó4  K  — ddl m}8m}9 |9€t        d«      ‚|€!|�|}ndt	        j
                  t        «      › �}|€d }:n;t        |«      };t        j                  t        j                  «      t        |;¬«      z   }:|€d }<nt        |¬«      }<|€d }=nt        |¬«      }=d }>|7rng }?|7D ]R  }@t        |@t        «      st        @«      ni @¥}At        |Ad   ¬«      j!                  «       |Ad<   |?j#                  |A«       ŒT t%        j&                  |?«      }>t%        j&                  |«      }Bt%        j&                  |«      }Ct%        j&                  |«      }D|5�t)        |5«      n
t)        i «      }E| �|xs i }| |d	<   |!�|xs i }|!|d
<   |"�|xs i }|"|d<   |#�|xs i }|#|d<   |$�|xs i }|$|d<   |%�|xs i }|%|d<   |&�|xs i }|&|d<   t+        |«      }t%        j&                  |«      }Ft-        |«       t%        j&                  |«      }Gt%        j&                  |xs i «      }H|}|}|}|}	 i d|
“d|“d|“d|“d|“d|(“d|“d|“d|“dF“d|“d|“d|“d|“d|=“d|“d|0“d |1i¥}I|'�|'Id!<   |rGId"<   i d#|“d$|“d%|:“d|“d&B“d'C“d|“d|“d|“d|“d(|“d)|)“d|“dF“d|“d|“d|“i d|<“d|“d*D“d"G“d+H“d|(“d,|“d-|“d.|>“d/|,“d0|-“d1|.xs g “d2|/“d |1“d3E“d4|6xs g “¥}Jt/        |J|3xs d5|4¬6«       t1        d7d5«      d8u rnt3        |¬9«      Jd:<   t5        j6                  J«      }Kt        |Kd&   t8        «      rt%        j:                  Kd&   «      |Kd&<   t        Kd'   t8        «      rt%        j:                  Kd'   «      |Kd'<   t        Kd   t8        «      rt%        j:                  Kd   «      |Kd<   t        Kd*   t8        «      r1d;Kd*   v r|8d8urt=        d<«      ‚t%        j:                  Kd*   «      |Kd*<   t        Kd"   t8        «      rt%        j:                  Kd"   «      |Kd"<   t?        t        d z  KjA                  d3«      «      }5|5�)t        |5t8        «      r	 tC        jD                  |5«      Kd3<   KjA                  d%d «      �)t        Kd%   t        «      rKd%   j!                  «       |Kd%<   |9��’|*�|*d=k(  r‘|d>k(  rkt?        d?|9jI                  Id=¬@«      ƒ d {  –—† «      }L|L€t        dA«      ‚tK        LjL                  «      dkD  rBtK        Jd   «      dk(  r1LjL                  Jd<   n!|dBk(  r|9jO                  Id=|¬C«      ƒ d {  –—† }L|*�|*d=k(  rIS tQ        jR                  dDi J¥d#tU        |¬E«      i¥«       |9jI                  |JdF¬@«      ƒ d {  –—† }MtW        |Md#d «      JdG<   tW        |Md#d «      }Nt        |Nt8        «      rtY        |9Nd |6¬H«      ƒ d {  –—†  tW        MdId «      JdI<   tW        |MdJd «      |JdJ<   tW        |MdKd «      |JdK<   |JjA                  d3«      }O|O�)t        Ot8        «      r	 tC        jD                  O«      Jd3<   |Jd,<   | d=k(  rJjg                  I«       JS # tB        jF                  $ r	 i Kd3<   Y �Œw xY w7 �Œ¦7 �Œ>7 Œö7 Œ´# tB        jF                  $ r i Jd3<   Y Œ`w xY w# t        $ rq}PtQ        jZ                  dLP«       tQ        jR                  t]        j^                  «       «       t        |Pt`        «      rP‚ta        tb        jd                  dMdNi¬O«      ‚d }P~Pww xY w­w)PNr   )r  r¥   z]Connect Proxy to database to generate keys - https://docs.litellm.ai/docs/proxy/virtual_keys r˜  rÉ   rX  rj  rY  rã  rä  r;  r<  r=  r>  r?  rR  r„   r�   r‡   r¿   r   rã   r¢  ru   r  re  rf  rg  rW  r9  rB  rh  r@  r…  rÅ  rÒ   rV  r5  r6  r7  r  rH  r:  rŠ  rß  rK  rˆ  r‰  r*  r(  rZ  r  F)rž   rÏ   rÇ   ÚDISABLE_KEY_NAMET©r-  Úkey_nameÚget_spend_routeszJget_spend_routes permission is only available for LiteLLM Enterprise usersr   r4  z&prisma_models.LiteLLM_UserTable | None)rž   r§  zFailed to create userr‘  )rž   r§  r8  zprisma_client: Creating Key= %srp  rt  rÄ  ©r¥   r‹  Úprevious_access_group_idsÚupdated_access_group_idsr  Ú
created_atÚ
updated_atzKlitellm.proxy.proxy_server.generate_key_helper_fn(): Exception occured - %srµ   zInternal Server Error.r¶   )4r©  r  r¥   r!  ÚsecretsÚtoken_urlsafer   r    r   rË   r	   rÌ   r   r<   r¸  rŒ   rK  r\  r°  r]  r!   r7   r_  rà   rj   r0   rI  Údeepcopyr’   Úloadsrµ  r   r¹   ÚyamlÚ	safe_loadÚ	YAMLErrorr4  r¾  ru   r‘  r   r­  r*   r8  rI   rµ   Ú	tracebackÚ
format_excr   r   r9  r    )Qr¦  rk  ru   r5  r6  r¢  r�  r‘  rŠ  rd  rR  rß  rj  rÅ  rt  r�   r‡   r¿   r7  r„   rã   re  r  rf  rg  rÎ  r8  rÒ   r9  rH  r…  r:  rã  rä  r;  r<  r=  r>  r?  r@  r   r  r§  rA  rˆ  r‰  r*  r(  rB  rh  r  rÏ   rÇ   rZ  r  rK  r  r¥   rV  Úduration_secondsra  rY  Úbudget_limits_jsonrc  rd  rT  Úaliases_jsonÚconfig_jsonÚpermissions_jsonÚrouter_settings_jsonÚmetadata_jsonÚmodel_max_budget_jsonÚbudget_fallbacks_jsonÚ	user_dataÚkey_dataÚsaved_tokenr  Úcreate_key_responseÚcreated_token_hashÚrouter_settings_valuer#  sQ                                                                                    r€   rÁ  rÁ  §  s†	  è ø€ ÷v GàÐÜÐwÓxÐxà€}Øˆ?Ø‰Eàœ'×/Ñ/Ô0OÓPÐQÐRˆEàÐØ‰ô #6°hÓ"?ÐÜ—,‘,œxŸ|™|Ó,¬yÐAQÔ/RÑRˆàÐ"Ø‰ä,Ð=PÔQˆàÐØ‰ä(¸ÔIˆð &*ÐÙØ%'ÐØ#ò 	*ˆFÜ$.¨v´tÔ$<”�V”À*ÀVÀ*ˆAÜ1À!ÐDUÑBVÔW×aÑaÓcˆAˆj‰MØ×&Ñ& qÕ)ð	*ô "ŸZ™ZÐ(;Ó<ÐäŸ*™* WÓ-€LÜŸ™ FÓ+€KÜ"Ÿj™j¨Ó5ÐØAPÐA\¤*¨_Ô"=ÔblÐmoÓbpÐð Ð"Ø’>˜rˆØ&5ˆÐ"Ñ#ØÐ"Ø’>˜rˆØ&5ˆÐ"Ñ#ØÐ Ø’>˜rˆØ$1ˆ�Ñ!ØÐ Ø’>˜rˆØ$1ˆ�Ñ!ØÐØ’>˜rˆØ!+ˆ�ÑØÐØ’>˜rˆØ'ˆ�ÑØÐØ’>˜rˆØ%ˆ�Ñä$ XÓ.€HÜŸ:™: hÓ/€MÜÐ.Ô/Ü#'§:¡:Ð.>Ó#?ÐÜ#'§:¡:Ð.>Ò.DÀ"Ó#EÐØ€IØ€IØ€IØ3Ððd
ð
Ø˜*ð
à˜*ð
ð �wð
ð ˜*ð	
ð
 �wð
ð ˜ð
ð ˜ð
ð �Uð
ð �fð
ð ˜ð
ð $Ð%:ð
ð ˜ð
ð ˜ð
ð ˜ð
ð ˜xð
ð  %Ð&<ð!
ð" ˜;ð#
ð$ #Ð$8ñ%
ˆ	ð( ÐØ!&ˆI�gÑÙð -BˆIÐ(Ñ)ð"
Ø�Uð"
à˜ð"
ð �wð"
ð �fð	"
ð
 �|ð"
ð �kð"
ð �Uð"
ð ˜.ð"
ð �wð"
ð �wð"
ð ˜ð"
ð ˜*ð"
ð $Ð%:ð"
ð ˜ð"
ð ˜ð"
ð  ˜ð!"
ð" Ð2ñ#"
ð$ ˜|ð%"
ð& %Ð&<ð'"
ð( Ð+ð)"
ð* Ð 5ð+"
ð, Ð 5ð-"
ð. ˜ð/"
ð0 ˜ð1"
ð2 �wð3"
ð4 Ð/ð5"
ð6 ˜*ð7"
ð8 ˜*ð9"
ð: ˜nÒ2°ð;"
ð< ˜ð="
ð> #Ð$8ð?"
ð@ Ð3ðA"
ðB Ð 0Ò 6°BñC"
ˆôJ 	!ØØ#Ò, uØ/õ	
ô Ð)¨5Ó1°TÑ9àä#5¸eÔ#DˆH�ZÑ Ü!Ÿ]™]¨8Ó4ˆÜ�k )Ñ,¬cÔ2Ü%)§Z¡Z°¸IÑ0FÓ%GˆK˜	Ñ"Ü�k (Ñ+¬SÔ1Ü$(§J¡J¨{¸8Ñ/DÓ$EˆK˜Ñ!Ü�k *Ñ-¬sÔ3Ü&*§j¡j°¸ZÑ1HÓ&IˆK˜
Ñ#Ü�k -Ñ0´#Ô6Ø! [°Ñ%?Ñ?ÀLÐX\ÑD\Ü Ð!mÓnÐnä)-¯©°KÀÑ4NÓ)OˆK˜Ñ&Ü�kÐ"4Ñ5´sÔ;Ü.2¯j©j¸ÐEWÑ9XÓ.YˆKÐ*Ñ+Üœt d™{¨K¯O©OÐ<MÓ,NÓOˆØÐ&¬:°oÄsÔ+Kð4Ü15·±ÀÓ1P�Ð-Ñ.ð
 �?‰?˜9 dÓ+Ð7¼JÀ{ÐS\ÑG]Ô_gÔ<hØ%0°Ñ%;×%EÑ%EÓ%GˆK˜	Ñ"ØÑ$ØÐ! Z°6Ò%9à Ò.Ü#Ø@Ø+×7Ñ7¸YÐSYÐ7ÓZ×Zó �Hð
  Ð'Ü'Ð(?Ó@Ð@ä˜8Ÿ?™?Ó+¨aÒ/´C¸ÀÑ8JÓ4KÈqÒ4PØ-5¯_©_˜ Ò*Ø =Ò0Ø%2×%>Ñ%>Ø&Ø#)Ø*;ð &?ó &÷  �Hð
 Ð%¨*¸Ò*>ð !Ð ô !×&Ñ&Ø1Ø>�8Ð>˜W¤j°uÔ&=Ñ>ôð 0=×/HÑ/HÈhÐchÐ/HÓ/i×)iÐä#*Ð+>ÀÈÓ#NˆH�ZÑ Ü(/Ð0CÀWÈdÓ(SÐÜÐ,¬cÔ2Ü6Ø"/Ø0Ø.2Ø-=ô	÷ ð ô 07Ð7JÐLbÐdhÓ/iˆHÐ+Ñ,Ü%,Ð-@À,ÐPTÓ%UˆH�\Ñ"Ü%,Ð-@À,ÐPTÓ%UˆH�\Ñ"ð ,4¯<©<Ð8IÓ+JÐ!Ø$Ð0´ZÐ@UÔWZÔ5[ð5Ü26·.±.ÐAVÓ2W�HÐ.Ñ/ð &€Hˆ[Ñà�vÒà�‰˜	Ô"à€Oøô[ —>‘>ò 4à13�Ð-Ô.ð4úð [ùð ùð  *jøð
ùô —~‘~ò 5à24�HÐ.Ó/ð5ûô ò 
Ü×"Ñ"Ð#pÐrsÔtÜ×"Ñ"¤9×#7Ñ#7Ó#9Ô:Ü�aœÔ'ØˆGÜÜ×=Ñ=ØÐ5Ð6ô
ð 	
ûð
üsÀ   ‚H \È#H+Z ÑY Ñ'A&Z ÓY3
ÓA*Z Ô8Y6Ô9Z Õ\Õ<Z ÖY9ÖAZ ×Y;×AZ ØY= Ø7\ÙY0Ù,Z Ù/Y0Ù0Z Ù6Z Ù9Z Ù;Z Ù=ZÚZ ÚZÚZ Ú	\Ú$A,\Ü\Ü\rÌ  c              ƒ   ó¶  K  — t        |¬«      }|rÅ|j                  �¹t        |j                  ||d¬«      ƒ d {  –—† }t        j                  �&dt        j                  v rt        j                  d   }nt        ddg¬«      }|�(t        | j                  || |t        j                  ¬«      S t        t        j                  d	d
|j                  › �i¬«      ‚y7 Œ�­w)NrÀ   Trƒ  rë   rÿ   r   r  r  rµ   z:Team not found in db, and user not proxy admin. Team id = r¶   F)rÁ   r¿   r/   rÚ   r  rs   r÷   r�   r=  Ú
KEY_DELETEr   r   rv  )rá   rÌ  r¥   rž  r  rÂ   r  s          r€   Ú_team_key_deletion_checkrg  Þ  sí   è ø€ ô &¨8Ô4€Ká�x×'Ñ'Ð3Ü"1Ø×$Ñ$Ø'Ø1Øô	#
÷ 
ˆ
ô ×*Ñ*Ð6Ð;PÔT[×TsÑTsÑ;sÜ#*×#BÑ#BÐCXÑ#YÑ ä#<Ø+2°FÐ*;ô$Ð ð Ð!Ü8Ø!2×!:Ñ!:Ø%Ø"3Ø$8Ü)×4Ñ4ôð ô  Ü"×5Ñ5ØÐ#]Ð^f×^nÑ^nÐ]oÐ!pÐqôð ð ð5
ús   ‚7C¹CºBCc              ƒ   ó¾  K  — ddl m} t        | ¬«      }|j                  t        j
                  j                  k(  ry|j                  |k(  ry|re| j                  �Yt        | j                  ||d¬«      ƒ d{  –—† }|€yt        ||¬«      ry| j                  �| j                  |j                  k(  ryy| j                  �| j                  |j                  k(  ryy7 Œc­w)	an  
    Check if user has permission to modify (delete/regenerate) a verification token.

    Rules:
    - Proxy admin can modify any key
    - Internal jobs service account can modify any key (for auto-rotation)
    - For team keys: only team admin or key owner can modify
    - For personal keys: only key owner can modify

    Args:
        key_info: The verification token to check
        user_api_key_cache: Cache for user API keys
        user_api_key_dict: The user making the request
        prisma_client: Prisma client for database access

    Returns:
        True if user can modify the key, False otherwise
    r   )Ú*LITELLM_INTERNAL_JOBS_SERVICE_ACCOUNT_NAMErÀ   TNrƒ  Frù  )Úlitellm.constantsri  rÁ   rã   rä   rå   ræ   r-  r¿   r/   rB   r�   )rÌ  rž  rá   r¥   ri  r  rÂ   s          r€   Úcan_modify_verification_tokenrk    sô   è ø€ õ0 Mä%¨8Ô4€Kð ×"Ñ"Ô&6×&BÑ&B×&HÑ&HÒHØð × Ñ Ð$NÒNØñ �x×'Ñ'Ð3ä"1Ø×$Ñ$Ø'Ø1Øô	#
÷ 
ˆ
ð ÐØô Ø/Øõ
ð ð ×ÑÐ'¨H×,<Ñ,<Ð@Q×@YÑ@YÒ,YØð ð ×ÑÐ#¨×(8Ñ(8Ð<M×<UÑ<UÒ(UØð ð;
ús   ‚A5CÁ7CÁ8A$Crÿ  c              ƒ   óH  K  — ddl m} g }	 |�r| D �cg c]  }t        |¬«      ‘Œ }}|} t        dt	        t        |«      «      j                  dd|ii¬«      ƒ d{  –—† «      }t        |«      dk(  rt        t        j                  d	d
i¬«      ‚|j                  t        j                  j                  k(  r|}	nNg }	|D ]G  }t        ||||¬«      ƒ d{  –—† r|	j!                  |«       Œ,t        t        j"                  d	di¬«      ‚ t%        |	|||¬«      ƒ d{  –—†  |j                  t        j                  j                  k(  rH|j'                  | ¬«      ƒ d{  –—† }
|
�Àt        |
«      t        | «      k7  r©| D �cg c]	  }||
vsŒ|‘Œ }}n”|	D �cg c]  }|j'                  |j(                  g¬«      ‘Œ! }}t+        j,                  |Ž ƒ d{  –—†  |	D �cg c]  }|j(                  ‘Œ }
}t        |
«      t        | «      k7  r | D �cg c]	  }||
vsŒ|‘Œ }}nt/        d«      ‚| D ]=  }|j;                  |«       t=        t        t>        |«      «      }|j;                  |«       Œ? |	D ]:  }|j(                  €ŒtA        ||j(                  |jB                  d¬«      ƒ d{  –—†  Œ< |
|dœ|fS c c}w 7 �ŒS7 �Œß7 �Œ›7 �Œ]c c}w c c}w 7 Œ÷c c}w c c}w # t.        $ rD}t1        j2                  d|«       t1        j4                  t7        j8                  «       «       |‚d}~ww xY w7 Œ„­w)aÆ  
    Helper that deletes the list of tokens from the database

    - check if user is proxy admin
    - check if user is team admin and key is a team key

    Args:
        tokens: List of tokens to delete
        user_id: Optional user_id to filter by

    Returns:
        Tuple[Optional[Dict], List[LiteLLM_VerificationToken]]:
            Optional[Dict]:
                - Number of deleted tokens
            List[LiteLLM_VerificationToken]:
                - List of keys being deleted, this contains information about the key_alias, token, and user_id being deleted,
                this is passed down to the KeyManagementEventHooks to delete the keys from the secret manager and handle audit logs
    r   r§   rp  zlist[LiteLLM_VerificationToken]rÅ  rå  r`  Nrµ   zNo keys foundr¶   ©rÌ  rž  rá   r¥   z)You are not authorized to delete this key©rÜ  r¥   rá   ry  )rÿ  ú'DB not connected. prisma_client is NonezOlitellm.proxy.proxy_server.delete_verification_tokens(): Exception occured - %srH  )r  Úfailed_tokens)"r©  r¥   rY   r   r¤   rg   r›   r¾  r   r   rv  rã   rä   rå   ræ   rk  r\  r  Ú$_persist_deleted_verification_tokensÚdelete_datarÅ  rÆ  Úgatherr!  r   r?  r­  rT  rU  Údelete_cacher*   r’   rI   r  )rÿ  rž  rá   ry  r¥   rp  rt  Úhashed_tokensr
  Úauthorized_keysÚdeleted_tokensrÅ  Údeletion_tasksr#  rx  Údeleted_keys                   r€   r  r  K  sL  è ø€ õ0 9à€Mð<ÚØ[aÖ.bÐTWÔ/DÈ3Ö/OÐ.bˆMÐ.bØ"ˆFÜJNØ1Ü#Ô$?ÀÓ$NÓO×YÑYØ" T¨=Ð$9Ð:ð Zó ÷ óKÐô Ð&Ó'¨1Ò,Ü#Ü &× 9Ñ 9Ø# _Ð5ôð ð
 !×*Ñ*Ô.>×.JÑ.J×.PÑ.PÒPØ"5‘à"$�Ø.ò �CÜ:Ø!$Ø+=Ø*;Ø&3ô	÷ ð ð (×.Ñ.¨sÕ3ä+Ü(.×(AÑ(AØ$+Ð-XÐ#Yôð ðô 7Ø$Ø+Ø"3Ø#5ô	÷ ð ð !×*Ñ*Ô.>×.JÑ.J×.PÑ.PÒPØ'4×'@Ñ'@ÈÐ'@Ó'O×!O�Ø!Ð-´#°nÓ2EÌÈVËÒ2TØ8>Ö$^¨uÀ%È~ÒB]¢UÐ$^�MÑ$^àbqÖ(rÐ[^¨×)BÑ)BÈ3Ï9É9È+Ð)BÕ)VÐ(r�Ð(rÜ—n‘n nÐ5×5Ð5à7FÖ!G° #§)£)Ð!G�Ð!GÜ�~Ó&¬#¨f«+Ò5Ø8>Ö$^¨uÀ%È~ÒB]¢UÐ$^�MÑ$^ô ÐEÓFÐFð ò 6ˆØ×'Ñ'¨Ô,ä!¤$¤s¨C£.Ó1ˆØ×'Ñ'¨Õ5ð	6ð 'ò ˆØ×ÑÑ(Ü2Ø+Ø%×+Ñ+Ø*5×*FÑ*FØ)-ô	÷ ñ ðð 'Ø&ñð ðð ùòY /cðùð ùðùð "Pûâ$^ùâ(rØ5úâ!Gùâ$^øô ò Ü×&Ñ&Ø]Ð_`ô	
ô 	×"Ñ"¤9×#7Ñ#7Ó#9Ô:Øˆûðúð úsä   ‚	L"ŒK “J)¦5K ÁJ.
ÁA6K ÃJ1ÃAK ÄJ4ÄA K ÅJ7Å!K Å<	J:ÆJ:Æ
K Æ$J?Æ5K ÇKÇK ÇKÇ(K È	KÈKÈK È!AL"É5&L"ÊL ÊL"Ê)K Ê1K Ê4K Ê7K Ê:K Ë
K Ë	LË?LÌLÌL"c           	      óê  — | sg S t        j                  t        j                  «      }g }| D ]Ä  }|j	                  «       }t
        j                  i |¥||j                  |j                  |dœ¥«      }|j	                  «       }|j                  dd«      }	|	�|	|d<   dD ](  }
|
|v sŒ||
   €Œt        j                  ||
   «      ||
<   Œ* dD ]  }|j                  |d«       Œ |j                  |«       ŒÆ |S )zOTransform verification tokens into deleted token records ready for persistence.)Ú
deleted_atÚ
deleted_byÚdeleted_by_api_keyry  r¢  Nr   )r5  r6  rH  r  Úmodel_spendr…  r:  rZ  )r  Úlitellm_organization_tabler  ÚidrK  )r   rË   r	   rÌ   r‰   Ú LiteLLM_DeletedVerificationTokenrÃ  r�   r-  r-  r°  r]  r\  )rÜ  rá   ry  r{  Úrecordsrt  Úkey_payloadÚdeleted_recordÚrecordÚorg_id_valueÚ
json_fieldÚrel_keys               r€   Ú1_transform_verification_tokens_to_deleted_recordsr‰  º  s"  € ñ Øˆ	ä Ÿ™¤X§\¡\Ó2€JØ€GØò (ˆØ—n‘nÓ&ˆÜ9×HÑHðØðà(Ø/×7Ñ7Ø&7×&?Ñ&?Ø&8òó
ˆð  ×*Ñ*Ó,ˆð  &Ÿz™z¨(°DÓ9ˆØÐ#Ø(4ˆFÐ$Ñ%ð	
ò 	DˆJð ˜VÒ#¨¨zÑ(:Ñ(FÜ%)§Z¡Z°°zÑ0BÓ%C��zÒ"ð	Dð
ò 	&ˆGð �J‰J�w Õ%ð	&ð 	�‰�vÕðQ(ðT €Nr‚   r‚  ÚtxzPrisma | Nonec              ƒ   ó®   K  — | sy|�%|j                   j                  | ¬«      ƒ d{  –—†  yt        |«      j                  | ¬«      ƒ d{  –—†  y7 Œ)7 Œ­w)zåSave deleted verification token records to the database.

    ``tx`` runs the write on that transaction's connection instead of a fresh
    one, so a caller batching this with other writes gets one all-or-nothing
    commit.
    NrÀ   )Ú litellm_deletedverificationtokenÚcreate_manyr¨   ©r‚  r¥   rŠ  s      r€   Ú(_save_deleted_verification_token_recordsr�  ò  sY   è ø€ ñ ØØ	€~Ø×1Ñ1×=Ñ=À7Ð=ÓK×KÐKØÜ
+¨MÓ
:×
FÑ
FÈGÐ
FÓ
T×TÑTð 	LøàTús!   ‚%A§A¨#AÁAÁAÁAc              ƒ   óX   K  — t        | ||¬«      }t        |||¬«      ƒ d{  –—†  y7 Œ­w)zKPersist deleted verification token records by transforming and saving them.)rÜ  rá   ry  rŽ  N)r‰  r�  )rÜ  r¥   rá   ry  rŠ  r‚  s         r€   rq  rq    s9   è ø€ ô GØØ+Ø-ô€Gô
 3ØØ#Øô÷ ò ús   ‚ *¢(£*r   c              ƒ   óÜ   K  — t        t        |«      «      j                  dd| ii¬«      ƒ d {  –—† }|D �cg c]  }|j                  ‘Œ }}t	        ||||¬«      ƒ d {  –—† S 7 Œ4c c}w 7 Œ­w)NrÒ   rå  r`  rþ  )r¤   rg   r›   rÅ  r  )r   rž  r¥   rá   ry  r
  rt  rÿ  s           r€   r  r    sƒ   è ø€ ô (5Ô5PÐQ^Ó5_Ó'`×'jÑ'jØ˜T ;Ð/Ð0ð (kó (÷ "Ðð +>Ö> 3�S—Y“YÐ>€FÐ>Ü+ØØ-Ø+Ø-ô	÷ ð ð"úò ?ðús,   ‚,A,®A#¯A,·A%Á
A,ÁA*ÁA,Á%A,Úcurrent_master_keyÚnew_master_keyc              ƒ   ó®
  K  — ddl }ddlm} 	 t        dt	        t        | «      «      j                  «       ƒ d{  –—† «      }|�r{|j                  |¬«      }t        j                  dt        |«      «       g }|D ]w  }	t        t        d&i |	¤Ž|| |d¬«      ƒ d{  –—† }
|
sŒ'|
j                  d	¬
«      }|j                  |d   «      |d<   |j                  |d   «      |d<   |j!                  |«       Œy t        j                  d«       | j"                  j%                  «       4 ƒd{  –—† }|}|j&                  j)                  «       ƒ d{  –—†  t        j                  dt        |«      «       |j&                  j+                  |¬«      ƒ d{  –—†  ddd«      ƒd{  –—†  t-        t/        «       d¬«      ƒ d{  –—†  	 t1        | «      j                  «       ƒ d{  –—† }|r†	 i }|D ]  }|j2                  dk(  sŒ|j4                  }Œ  |r^|j7                  |¬«      }|j9                  ||¬«      }|r7t1        | «      j;                  ddid|j                  |«      i¬«      ƒ d{  –—†  	 t=        | |j>                  xs t@        |¬«      ƒ d{  –—†  	 tG        | |¬«      ƒ d{  –—†  	 tI        | |¬«      ƒ d{  –—†  	 tK        | |¬«      ƒ d{  –—†  	 tM        | «      j                  «       ƒ d{  –—† }|rÒddl'm(} |D ]§  }	 |jS                  |«      } ||||¬«      }|j                  d	¬
«      }d |v r|j                  |d    «      |d <   d!|v r|j                  |d!   «      |d!<   tM        | «      j;                  d"|jT                  ii |¥d#|j>                  i¥¬«      ƒ d{  –—†  Œ© t        j                  d%t        |«      «       yy7 �Œ“# t        $ r d}Y �Œ›w xY w7 �ŒH7 �Œ½7 �Œœ7 �Œ\7 �ŒO# 1 ƒd{  –—†7  sw Y   �Œ`xY w7 �ŒK7 �Œ,# t        $ r d}Y �Œ8w xY w7 �Œ¹7 �Œ“# t        $ r*}t        jB                  dtE        |«      «       Y d}~�Œ¿d}~ww xY w7 �Œ¶# t        $ r*}t        jB                  dtE        |«      «       Y d}~�Œâd}~ww xY w7 �ŒÙ# t        $ r*}t        jB                  dtE        |«      «       Y d}~�Œd}~ww xY w7 �Œü# t        $ r*}t        jB                  dtE        |«      «       Y d}~�Œ(d}~ww xY w7 �Œ# t        $ r d}Y �Œw xY w7 �Œv# t        $ r,}t        jV                  d$|jT                  |«       Y d}~�ŒLd}~ww xY w­w)'aR  
    Rotate the master key

    1. Get the values from the DB
        - Get models from DB
        - Get config from DB
    2. Decrypt the values
        - ModelTable
            - [{"model_name": "str", "litellm_params": {}}]
        - ConfigTable
    3. Encrypt the values with the new master key
    4. Update the values in the DB
    r   N)Úproxy_configzlist[object])Ú
new_modelsz2ABLE TO DECRYPT MODELS - len(decrypted_models): %sF)Úmodel_paramsrá   r¥   Únew_encryption_keyÚshould_create_model_in_dbTr†  Úlitellm_paramsÚ
model_infozResetting proxy model tablezCreating %s modelsrÀ   r–   )r¿  Úobject_typeÚenvironment_variables)r�  )r�  r˜  Ú
param_nameÚparam_value©r�   rž   )r¥   Ú
touched_byr“  z+Failed to rotate MCP server credentials: %s)r¥   r“  z)Failed to rotate MCP user credentials: %sz&Failed to rotate MCP user env vars: %sz,Failed to rotate SSO identity assertions: %s)Úupdate_db_credential)Údb_credentialÚupdated_patchr˜  Úcredential_valuesÚcredential_infoÚcredential_namer‰  z&Failed to re-encrypt credential %s: %sz<Successfully re-encrypted %s credentials with new master keyr}   ),Úprismar©  r•  r   r¤   ra   r›   r!  Údecrypt_model_list_from_dbr   r­  r¾  rH   rp   r‰   ÚJsonr\  ÚdbrŠ  r–   Údelete_manyr�  r9   r8   r°   rž  rŸ  Ú!_decrypt_and_set_db_env_variablesÚ_encrypt_env_variablesr    r#   r�   r   rº   r’   r$   r%   r&   r®   Ú,litellm.proxy.credential_endpoints.endpointsr¢  Údecrypt_credentialsr§  rµ   )r¥   rá   r’  r“  r¨  r•  ru   Údecrypted_modelsr–  rî  Ú	new_modelÚ_dumpedÚtx_ctxrŠ  r6  Úenvironment_variables_dictÚcÚdecrypted_env_varsÚencrypted_env_varsr#  Úcredentialsr¢  ÚcredÚdecrypted_credÚencrypted_credÚ
_cred_datas                             r€   Ú_rotate_master_keyr¾  -  s¤  è ø€ ó& å7ðÜ"Ø¤-´ÀÓ0NÓ"O×"YÑ"YÓ"[×[ó
ˆò Ø".×"IÑ"IÐU[Ð"IÓ"\ÐÜ×"Ñ"Ð#WÔY\Ð]mÓYnÔoØ57ˆ
Ø%ò 	+ˆEÜ.Ü'Ñ0¨%Ñ0Ø"3Ø+Ø#1Ø*/ô÷ ˆIò Ø#×.Ñ.¸DÐ.ÓA�Ø,2¯K©K¸Ð@PÑ8QÓ,R�Ð(Ñ)Ø(.¯©°G¸LÑ4IÓ(J�˜Ñ%Ø×!Ñ! 'Õ*ð	+ô 	×"Ñ"Ð#@ÔAØ ×#Ñ#×&Ñ&Ó(÷ 	ð 	¨FØ#)ˆBØ×,Ñ,×8Ñ8Ó:×:Ð:Ü ×&Ñ&Ð';¼SÀ»_ÔMØ×,Ñ,×8Ñ8Øð 9ó ÷ ð ÷		÷ 	ô $Ô0HÓ0JÐXqÔr×rÐrðÜ$ ]Ó3×=Ñ=Ó?×?ˆñ ØbØ%'Ð"Øò 	;ˆAØ�|‰|Ð6Ó6Ø-.¯]©]Ñ*ð	;ñ &Ø(4×(VÑ(VØ&@ð )Wó )Ðð )5×(KÑ(KØ&8Ø#1ð )Ló )Ðñ
 "Ü# MÓ2×9Ñ9Ø'Ð)@ÐAØ'¨¯©Ð5GÓ)HÐIð :ó ÷ ð ð\Ü6Ø'Ø(×0Ñ0ÒLÔ4LØ)ô
÷ 	
ð 	
ðZÜ4Ø'Ø)ô
÷ 	
ð 	
ðWÜ1Ø'Ø)ô
÷ 	
ð 	
ð]Ü7Ø'Ø)ô
÷ 	
ð 	
ðÜ.¨}Ó=×GÑGÓI×Iˆñ ÝUàò 	ˆDðØ!-×!AÑ!AÀ$Ó!G�Ù!5Ø"&Ø"0Ø'5ô"�ð
 ,×6Ñ6ÀDÐ6ÓI�
Ø&¨*Ñ4Ø6<·k±kÀ*ÐM`ÑBaÓ6b�JÐ2Ñ3Ø$¨
Ñ2Ø4:·K±KÀ
ÐK\Ñ@]Ó4^�JÐ0Ñ1Ü(¨Ó7×>Ñ>Ø,¨d×.BÑ.BÐCðØ$ðà$Ð&7×&?Ñ&?ñð ?ó ÷ ñ ð	ô0 	×"Ñ"Ð#aÔcfÐgrÓcsÕtð7 ðK \úäò Ø‹ðúðùð	ùà:ùðùð		ù÷ 	÷ 	ò 	úð 	sùð @úÜò Ø‹ðúð(ùð	
úô
 ò \Ü×$Ñ$Ð%RÔTWÐXYÓTZ×[Ò[ûð\úð
	
úô ò ZÜ×$Ñ$Ð%PÔRUÐVWÓRX×YÒYûðZúð
	
úô ò WÜ×$Ñ$Ð%MÌsÐSTËv×VÒVûðWúð
	
úô ò ]Ü×$Ñ$Ð%SÔUXÐYZÓU[×\Ò\ûð]úð
 JúÜò Ø‹ðúð$úô ò Ü$×*Ñ*Ð+SÐUY×UiÑUiÐklÔmåûðüsY  ‚UŽ+O ¹O
ºO ÁAUÂO!ÂUÂ!BUÄ'O$Ä(UÄ+ O0ÅO'ÅAO0ÆO*ÆO0ÆUÆO-ÆUÆ;PÆ<UÇP ÇP	ÇP Ç"UÇ<A)UÉ%PÉ&UÉ+#P$ ÊP!ÊP$ ÊQ Ê$QÊ%Q Ê*R Ê:RÊ;R Ë S ËSËS ËT Ë2TË3T Ë7UÌBTÎ$TÎ%TÎ)#UÏO ÏOÏUÏOÏUÏ$UÏ'O0Ï*O0Ï-UÏ0PÏ6O9Ï7PÏ>	UÐ	P ÐPÐUÐPÐUÐ!P$ Ð$	QÐ-QÑUÑQÑUÑQ Ñ	RÑ&RÒUÒRÒUÒR Ò	S	ÒSÒ>UÓS	Ó	UÓS Ó	TÓS=Ó7UÓ=TÔUÔT ÔTÔUÔTÔUÔTÔ	UÔ&!UÕUÕUÕUc                 ó¤   — ddl m} | j                  t        j                  j
                  k7  r#t        dd|j                  j
                  i¬«      ‚y )Nr   r&  r´   rµ   r¶   )r8  r¶  rã   rä   rå   ræ   r   Únot_allowed_access)rá   r¶  s     r€   Ú_require_proxy_adminrÁ  É  sK   € Ý6à×"Ñ"Ô&6×&BÑ&B×&HÑ&HÒHÜØØÐ.×AÑA×GÑGÐHô
ð 	
ð Ir‚   z/credentials/migrate-encryptionzcredential managementz5If true, scan and report without writing any changes.Údry_runc              ƒ   óà   K  — ddl m} ddlm} ddlm} t        | «       |€#t        dd|j                  j                  i¬«      ‚ ||| |¬	«      ƒ d{  –—† }d
||j                  «       dœS 7 Œ­w)uC  
    Re-encrypt all at-rest credentials into the AES-256-GCM (``v2:gcm:``) format.

    Admin only. Requires ``general_settings.encryption_algorithm: aes-256-gcm``.
    Idempotent and resumable â€” re-running skips already-migrated values. Pass
    ``dry_run=true`` for a non-mutating scan (equivalent to ``--check``).
    r   r&  )Úmigrate_encryptionr§   Nr  rµ   r¶   )r¥   rá   rÂ  Úsuccess)r   rÂ  Úreport)r8  r¶  Ú7litellm.proxy.management_endpoints.credential_migrationrÄ  r©  r¥   rÁ  r   r:  ræ   Úas_dict)rá   rÂ  r¶  rÄ  r¥   rÆ  s         r€   Úmigrate_encryption_endpointrÉ  Ó  s~   è ø€ õ& 7õõ 9äÐ*Ô+ØÐÜØØÐ.×EÑE×KÑKÐLô
ð 	
ñ
 -Ø#Ø+Øô÷ €Fð
  ¨G¸v¿~¹~Ó?OÑPÐPðús   ‚AA.ÁA,ÁA.z%/credentials/migrate-encryption/checkc              ƒ   óÚ   K  — ddl m} ddlm} ddlm} t        | «       |€#t        dd|j                  j                  i¬«      ‚ ||¬«      ƒ d{  –—† }d	|j                  «       d
œS 7 Œ­w)zä
    Read-only residual scan for compliance attestation. Reports how many at-rest
    values are still in the legacy format. ``residual_legacy == 0`` attests no
    legacy ciphertext remains. Admin only; performs no writes.
    r   r&  )Úcheck_encryptionr§   Nr  rµ   r¶   rÅ  )r   rÆ  )r8  r¶  rÇ  rË  r©  r¥   rÁ  r   r:  ræ   rÈ  )rá   r¶  rË  r¥   rÆ  s        r€   Úcheck_encryption_endpointrÌ  û  sp   è ø€ õ 7õõ 9äÐ*Ô+ØÐÜØØÐ.×EÑE×KÑKÐLô
ð 	
ñ
 +¸ÔG×G€FØ¨6¯>©>Ó+;Ñ<Ð<ð Hús   ‚AA+ÁA)ÁA+c              ƒ   ó®  K  — | r°| j                   �¤t        | j                   «      ƒ d {  –—†  | j                   j                  d«      st        t        j
                  ddi¬«      ‚t        | j                   «      t        k  r%t        t        j
                  ddt        › d�i¬«      ‚| j                   }|S dt        j                  t        «      › �}|S 7 Œ©­w)Nr˜  rµ   z„New key must start with 'sk-'. This is to distinguish a key hash (used by litellm for logging / internal logic) from the actual key.r¶   zNew key must be at least rœ  )rT  r¼   r½  r   r   rw  r¾  r   rM  rN  r   )rž   Ú	new_tokens     r€   Úget_new_tokenrÏ    sÒ   è ø€ Ù�—‘Ð(ä'¨¯©Ó5×5Ð5Ø�|‰|×&Ñ& uÔ-ÜÜ"×7Ñ7àð  dðôð ô ˆt�|‰|ÓÔ8Ò8ÜÜ"×7Ñ7ØÐ#<Ô=VÐ<WÐWhÐ!iÐjôð ð —L‘Lˆ	ð Ðð œ'×/Ñ/Ô0OÓPÐQÐRˆ	ØÐð! 	6ús   ‚'C©CªB*CrW   Úold_token_hashÚnew_token_hashrU  c              ƒ   ó   K  — |xs t        j                  dd«      }|sy	 t        |«      }|dk  ry	 t        j                  t        j                  «      t        |¬«      z   }t        | «      j                  d|i|||dœ||d	œd
œ¬«      ƒ d{  –—†  t	        j                  d||«       y# t        $ r t	        j
                  d|«       Y yw xY w7 ŒA# t        $ r }t	        j
                  d|«       Y d}~yd}~ww xY w­w)a—  
    Insert old key into deprecated table so it remains valid during grace period.

    Uses upsert to handle concurrent rotations gracefully.

    Parameters:
        prisma_client: DB client
        old_token_hash: Hash of the old key being rotated out
        new_token_hash: Hash of the new replacement key
        grace_period: Duration string (e.g. "24h", "2d") or None/empty for immediate revoke
    Ú!LITELLM_KEY_ROTATION_GRACE_PERIODr7  NzBInvalid grace_period format: %s. Expected format like '24h', '2d'.r   rÉ   rÅ  )rÅ  Úactive_token_idÚ	revoke_at)rÔ  rÕ  )r±  r    r   z.Deprecated key retained for %s (revoke_at: %s)z4Failed to insert deprecated key for grace period: %s)ÚosÚgetenvr    rµ  r   rº   r   rË   r	   rÌ   r   rª   Úupsertr­  r!  )r¥   rÐ  rÑ  rU  Úgrace_period_valueÚgrace_secondsrÕ  Údeprecated_errs           r€   Ú_insert_deprecated_keyrÜ  /  s#  è ø€ ð" !-Ò b´·	±	Ð:]Ð_aÓ0bÐÙØðÜ2Ð3EÓFˆð ˜ÒØð
Ü#Ÿ<™<¬¯©Ó5¼	È-Ô8XÑXˆ	Ü2°=ÓA×HÑHØ˜NÐ+ð ,Ø'5Ø!*ñð (6Ø!*ññ
ð Ió 
÷ 	
ð 	
ô 	×"Ñ"Ø<ØØõ	
øô5 ò Ü×$Ñ$ØPØô	
ñ 	ðúð	
ùô& ò 
Ü×$Ñ$ØBØ÷	
ñ 	
ûð
üsc   ‚C>¡B+ ¬C>³AC ÂCÂC Â*C>Â+CÃ
C>ÃCÃC>ÃC Ã	C;ÃC6Ã1C>Ã6C;Ã;C>Ú	key_in_dbÚhashed_api_keyc        	   	   ƒ   ót  K  — ddl m}	 t        |||¬«       |��|j                  �ut	        |dd«      }
|j
                  duxr' |j
                  t        j                  j                  k(  }|j                  |
k7  r"|s t        ||j                  | ¬«      ƒ d{  –—†  |�Ot	        |dd«      }t        |t        |t        «      r|nd|d¬	«       t        |t        |t        «      r|nd|d¬	«       t        |¬
«      ƒ d{  –—† } |	|«      }t        |¬«      }||dœ}i }|�dt!        |d¬«       t#        ||¬«      ƒ d{  –—† }|j%                  d«      }||j&                  k7  rt)        |¬«       t+        j,                  d|«       |j/                  |«       | j1                  |¬
«      }t3        | |||r|j4                  nd¬«      ƒ d{  –—†  t7        t9        | «      «      j/                  d|it;        |«      ¬«      ƒ d{  –—† }|�t        |«      ni }||d<   |j=                  d«      |d<   |s|rt?        tA        |«      ||¬«      ƒ d{  –—†  tC        | ||||¬«      ƒ d{  –—†  tD        jG                  |«      }tI        jJ                  tM        jN                  |||||¬«      «       |S 7 �Œ7 �Œ°7 �Œt7 Œì7 Œ¶7 Œm7 ŒW­w)zEGenerate new token, update DB, invalidate cache, and return response.r   )r*   rŸ  Nr   rŸ  r  rt  r}  rÀ   rE  )rÅ  rF  Fr‚  rj  rÒ   r—  znon_default_values: %s)r¥   rÐ  rÑ  rU  rÅ  r   rÄ  r‰  )r¥   Úprevious_key_tokenÚnew_key_tokenrž   r4  rŒ  )(r©  r*   r=  r   r8  rã   rä   rå   ræ   r¿  r2   r¸  rŒ   r1   rÏ  r0   rx  re  r¹   rÒ   r»  r   r­  r    r¯  rÜ  rU  r¤   rg   rL   r-  r+   rY   rJ   rÂ  rÃ  rÆ  rÇ  r>   Úasync_key_rotated_hook)r¥   rÝ  rÞ  rt  rž   rá   ry  rž  r~  r*   r­  rÙ  Ú_existing_key_metadatarÎ  rÑ  Únew_token_key_namer‘  rF  rÃ  Újsonified_update_dataÚupdated_tokenÚupdated_token_dictr¨  s                          r€   Ú!_execute_virtual_key_regenerationrè  l  s  è ø€ õ 6ô .ØØ"Ø+õð Ð˜D×0Ñ0Ð<Ü")¨)Ð5FÈÓ"MÐà×'Ñ'¨tÐ3ò RØ!×+Ñ+Ô/?×/KÑ/K×/QÑ/QÑQð 	ð ×ÑÐ#3Ò3¹OÜ5Ø"3Ø $× 4Ñ 4Ø+ô÷ ð ð ÐÜ(/°	¸:ÀtÓ(LÐÜ5ØÜ8BÐCYÔ[_Ô8`Ñ4ÐfjØ/Øõ		
ô 	9ØÜ8BÐCYÔ[_Ô8`Ñ4ÐfjØ/Øõ		
ô +°Ô5×5€IÙ& yÓ1€NÜ 2¸9Ô EÐØ*Ð8JÑK€KàÐØÐä& t¸5ÕAÜ#:ÀÐW`Ô#a×aÐà1×5Ñ5°kÓBˆØ˜I×/Ñ/Ò/Ü&°Õ?Ü×"Ñ"Ð#;Ð=OÔPØ×ÑÐ)Ô*Ø9F×9UÑ9UÐ[fÐ9UÓ9gÐô !Ø#Ø%Ø%Ù*.�T×&Ò&°Dô	÷ ð ô DQÜ# MÓ2óDç�fØ˜Ð'Ü%Ð&;Ó<ð ó ÷>€Mð KXÐJc´4¸Ô3FÐikÐØ )Ð�uÑØ%7×%;Ñ%;¸GÓ%DÐ�zÑ"á™Ü&Ü.¨sÓ3Ø1Ø/ô
÷ 	
ð 	
ô 8Ø#Ø)Ø$ØØ"ô÷ ð ô *×8Ñ8Ð9KÓL€HÜ×ÑÜ×6Ñ6ØØ&ØØ/Ø1ô	
ôð €Oðgùð* 6ùð bùðøð>øð	
øðús‚   ‚BJ8ÂJ'ÂA$J8Ã:J*Ã;>J8Ä9J-Ä:B	J8ÇJ0Ç7J8Ç;J2Ç<A
J8ÉJ4ÉJ8ÉJ6ÉA	J8Ê*J8Ê-J8Ê0J8Ê2J8Ê4J8Ê6J8z/key/{key:path}/regeneratez/key/regeneratec              ƒ   ó”  K  — 	 ddl m}m}m}m}m}m}	 |�et        |j                  |d|j                  v ¬«       t        ||¬«       t        ||¬«       t        t        |i «      j                  d«      |d¬«       |r|j                  r|j                  n| }
|duxr |j                  duxr t!        |
|¬	«      }|dur(|s&t#        d
t$        j&                  j(                  › �«      ‚|r|j                  r|j                  n| } | st+        dddi¬«      ‚|€t+        t,        j.                  ddi¬«      ‚t!        | |¬	«      }|�{|ry|rw|j                  €t+        t,        j0                  ddi¬«      ‚t3        ||||j                  ¬«      ƒ d{  –—†  t5        |j                  |j                  |j                  d¬«      S d| vr| }n || «      }t7        t9        |«      «      j;                  d|i¬«      ƒ d{  –—† }|€!t+        t,        j<                  dd| › d�i¬«      ‚t?        j@                  |tB        jD                  |||	¬«      ƒ d{  –—†  tG        ||	||¬«      ƒ d{  –—† st+        t,        jH                  ddi¬«      ‚|�ü|jJ                  s|jL                  �äd}|jN                  �!tQ        |jN                  ||	d¬«      ƒ d{  –—† }|jR                  tT        jV                  j(                  k(  }t?        jX                  |||jJ                  ¬«       t[        |jL                  «      }t]        ||||¬«      ƒ d{  –—† }|�t_        d%i |¤Ž|_&        |}ta        |||¬«      ƒ d{  –—†  tc        |||¬«      ƒ d{  –—†  te        jf                  dti        |d d«      «       te        jj                  d!|«       |�tm        |tn        «      sd}tq        |g|||¬"«      ƒ d{  –—†  ts        |||| ||||	|¬#«	      ƒ d{  –—† S 7 �Œs7 �Œ7 �Œ¼7 �Œ¨7 �ŒE7 ŒÒ7 Œª7 Œ–7 Œ57 Œ# tt        $ r&}te        jv                  d$|«       ty        |«      ‚d}~ww xY w­w)&ay  
    Regenerate an existing API key while optionally updating its parameters.

    Parameters:
    - key: str (path parameter) - The key to regenerate
    - data: Optional[RegenerateKeyRequest] - Request body containing optional parameters to update
        - key: Optional[str] - The key to regenerate.
        - new_master_key: Optional[str] - The new master key to use, if key is the master key.
        - new_key: Optional[str] - The new key to use, if key is not the master key. Must start with 'sk-' and be at least 16 characters long. If both set, new_master_key will be used.
        - key_alias: Optional[str] - User-friendly key alias
        - user_id: Optional[str] - User ID associated with key
        - team_id: Optional[str] - Team ID associated with key
        - models: Optional[list] - Model_name's a user is allowed to call
        - tags: Optional[List[str]] - Tags for organizing keys (Enterprise only)
        - spend: Optional[float] - Amount spent by key
        - max_budget: Optional[float] - Max budget for key
        - model_max_budget: Optional[Dict[str, BudgetConfig]] - Model-specific budgets {"gpt-4": {"budget_limit": 0.0005, "time_period": "30d"}}
        - budget_fallbacks: Optional[Dict[str, List[str]]] - Per-model fallback chain tried in order when that model's own `model_max_budget` is exceeded, e.g. {"gpt-4o": ["gpt-4o-mini"]}.
        - budget_duration: Optional[str] - Budget reset period ("30d", "1h", etc.)
        - soft_budget: Optional[float] - Soft budget limit (warning vs. hard stop). Will trigger a slack alert when this soft budget is reached.
        - max_parallel_requests: Optional[int] - Rate limit for parallel requests
        - metadata: Optional[dict] - Metadata for key. Example {"team": "core-infra", "app": "app2"}
        - tpm_limit: Optional[int] - Tokens per minute limit
        - rpm_limit: Optional[int] - Requests per minute limit
        - model_rpm_limit: Optional[dict] - Model-specific RPM limits {"gpt-4": 100, "claude-v1": 200}
        - model_tpm_limit: Optional[dict] - Model-specific TPM limits {"gpt-4": 100000, "claude-v1": 200000}
        - allowed_cache_controls: Optional[list] - List of allowed cache control values
        - duration: Optional[str] - Key validity duration ("30d", "1h", etc.)
        - permissions: Optional[dict] - Key-specific permissions
        - guardrails: Optional[List[str]] - List of active guardrails for the key
        - blocked: Optional[bool] - Whether the key is blocked
        - grace_period: Optional[str] - Duration to keep old key valid after rotation (e.g. "24h", "2d"). Omitted = immediate revoke. Env: LITELLM_KEY_ROTATION_GRACE_PERIOD


    Returns:
    - GenerateKeyResponse containing the new key and its updated parameters

    Example:
    ```bash
    curl --location --request POST 'http://localhost:4000/key/sk-1234/regenerate'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data-raw '{
        "max_budget": 100,
        "metadata": {"team": "core-infra"},
        "models": ["gpt-4", "gpt-3.5-turbo"]
    }'
    ```

    Note: This is an Enterprise feature. It requires a premium license to use.
    r   )r*   Ú
master_keyr  r¥   r~  rž  Nr*  r/  rƒ  Tr�  )r-  Ú_master_keyz4Regenerating Virtual Keys is an Enterprise feature, rÓ   rµ   zNo key passed in.r¶   ro  zNew master key is required.)r¥   rá   r’  r“  )rt  rÅ  rF  rV  ÚskrÅ  r`  úKey ú not found.r�  rm  z-You are not authorized to regenerate this keyrƒ  r  r“  r–  z(Key regeneration requested: key_alias=%srÒ   zkey_in_db: %srn  )	r¥   rÝ  rÞ  rt  rž   rá   ry  rž  r~  zError regenerating key: %sr}   )=r©  r*   rê  r  r¥   r~  rž  rF  r*  r6  r@   rJ  r2  r¹   rt  r“  rU   rµ  r¶  r·  ræ   r   r   r9  rw  r¾  rÂ  r¤   rg   ra  rv  rS   rŽ  r=  ÚKEY_REGENERATErk  r  r  r  r¿   r/   rã   rä   rå   r  r  rP   r¤  rQ   rR   r   r  r8  r­  r¸  r’   rq  rè  r!  r?  rZ   )rt  rž   rá   ry  r*   rê  r  r¥   r~  rž  Úregenerate_target_keyÚis_master_key_regenerationÚ_is_master_key_validrÞ  Ú
_key_in_dbÚregenerate_team_tableÚ_regen_is_proxy_adminÚ_regen_object_permission_dictrÓ  r#  s                       r€   Úregenerate_key_fnr÷  â  sæ  è ø€ ðNJ+÷	
÷ 	
ð ÐÜ3Ø#×2Ñ2Ø"3Ø,<À×@UÑ@UÐ,Uõô
 8ØØ"3õô 1ØØ"3õô 4Ü.¨t°RÓ8×<Ñ<Ð=MÓNØ"3Ø#'õñ 48¸D¿HºH t§x¢xÈ#Ðà˜Ðò VØ×#Ñ#¨4Ð/òVäÐ'<È*ÔUð 	#ð  Ñ$Ñ-GäØFÔGX×GiÑGi×GoÑGoÐFpÐqóð ñ
  4§8¢8ˆd�hŠh°ˆÙÜ¨C¸ÐBUÐ8VÔWÐWð Ð ÜÜ"×AÑAØÐ!JÐKôð ô
 '5¸SÈjÔ&YÐàÐ!¡dÑ/CØ×"Ñ"Ð*Ü#Ü &× ;Ñ ;Ø#Ð%BÐCôð ô %Ø+Ø"3Ø#-Ø#×2Ñ2ô	÷ ð ô 'Ø×'Ñ'Ø×)Ñ)Ø×,Ñ,Øô	ð ð �s‰?Ø ‰Ná'¨›_ˆNä"/Ô0KÈMÓ0ZÓ"[×"gÑ"gØ˜NÐ+ð #hó #
÷ 
ˆ
ð ÐÜÜ"×5Ñ5Ø 4¨ u¨KÐ!8Ð9ôð ô )×XÑXØ/Ü%×4Ñ4Ø'Ø'Ø1ô
÷ 	
ð 	
ô 3ØØ1Ø/Ø'ô	
÷ 
ð 
ô  Ü"×5Ñ5ØÐ!PÐQôð ð
 Ð ×!6Ò!6¸$×:PÑ:PÐ:\ØGKÐ!Ø×!Ñ!Ð-Ü.=Ø&×.Ñ.Ø"/Ø'9Ø"&ô	/÷ )Ð%ð ,=×+FÑ+FÔJZ×JfÑJf×JlÑJlÑ+lÐ!Ü&×NÑNØ"3Ø0Ø!%×!6Ñ!6õô
 -GÀt×G]ÑG]Ó,^Ð)Ü8]Ø"?Ø.Ø+Ø4ô	9÷ 3Ð(ð ,Ð7Ü)EÑ)eÐHdÑ)e�Ô&Ø0LÐ-Ü8Ø"?Ø.Ø4ô÷ ð ô
 :Ø"?Ø.Ø4ô÷ ð ô 	×!Ñ!Ø6Ü�J ¨TÓ2ô	
ô 	×"Ñ" ?°JÔ?ð Ð)´*Ð=OÔQTÔ2UØ!%Ðô 3Ø�Ø'Ø/Ø1ô	
÷ 	
ð 	
ô 7Ø'Ø Ø)ØØØ/Ø1Ø1Ø/ô

÷ 

ð 
	
ðSùð$
ùð	
ùð
ùð)ùð3øðøð
øð(	
øð

ùô ò +Ü×&Ñ&Ð'CÀQÔGÜ'¨Ó*Ð*ûð+üsí   ‚Q„FP Æ
O=Æ0P Æ;QÆ<8P Ç4P Ç5AP ÉPÉP ÉPÉA%P ËP	ËA4P Ì9PÌ:)P Í#PÍ$P Í9PÍ:A"P ÏPÏP Ï8PÏ9P Ï<QÏ=P Ð P ÐP ÐP Ð	P ÐP ÐP ÐP ÐP ÐP Ð	QÐ!Q Ñ QÑQc              ƒ   ó  K  — |j                   t        j                  j                  k(  ry | j                  �1t        | j                  ||d¬«      ƒ d {  –—† }|�t        ||¬«      ry t        t        j                  ddi¬«      ‚7 Œ1­w)NTrƒ  rù  rµ   z:You must be a proxy admin or team admin to reset key spendr¶   )
rã   rä   rå   ræ   r¿   r/   rB   r   r   r  )rÝ  rá   r¥   rž  rÂ   s        r€   Ú"_check_proxy_or_team_admin_for_keyrù  ö  s’   è ø€ ð ×"Ñ"Ô&6×&BÑ&B×&HÑ&HÒHØà×ÑÐ$Ü"1Ø×%Ñ%Ø'Ø1Øô	#
÷ 
ˆ
ð Ð!Ü"Ø"3Ø#õð ä
Ü×-Ñ-ØÐUÐVôð ð
ús   ‚ABÁBÁ2BÚreset_toc           	      ó  — t        | t        t        f«      st        t        j
                  ddi¬«      ‚t        | «      } | dk  rt        t        j
                  ddi¬«      ‚|j                  xs d}| |kD  r$t        t        j
                  dd| › d|› d	�i¬«      ‚|j                  }|j                  �"t        |j                  d
d «      }|�	|�||k  r|}|�)| |kD  r$t        t        j
                  dd| › d|› d	�i¬«      ‚| S )Nrµ   zreset_to must be a floatr¶   r   zreset_to must be >= 0r3  z
reset_to (z) must be <= current spend (rº  rR  z) must be <= budget ()
r¸  Úintrr  r   r   rw  r¢  rR  r  r8  )rú  rÝ  Úcurrent_spendrR  Úbudget_max_budgets        r€   Ú_validate_reset_spend_valuerÿ    s3  € Ü�h¤¤e Ô-ÜÜ×3Ñ3ØÐ7Ð8ô
ð 	
ô
 �X‹€Hà�!‚|ÜÜ×3Ñ3ØÐ4Ð5ô
ð 	
ð
 %Ÿ?™?Ò1¨c€MØ�-ÒÜÜ×3Ñ3Ø˜z¨(¨Ð3OÐP]ÈÐ^_Ð`Ðaô
ð 	
ð
 ×%Ñ%€JØ×%Ñ%Ð1Ü#*¨9×+IÑ+IÈ<ÐY]Ó#^ÐØÐ(ØÐ!Ð%6¸Ò%CØ.�
àÐ (¨ZÒ"7ÜÜ×3Ñ3Ø˜z¨(¨Ð3HÈÈÐTUÐVÐWô
ð 	
ð
 €Or‚   rÄ  ræ   c              ƒ   óÂ  K  — ddl m}m} |j                  j	                  | |d¬«       |j
                  �'	 |j
                  j                  | |d¬«      ƒ d{  –—†  d| › �}|j                  j	                  |||¬«       t        | |d¬«      ƒ d{  –—†  t        |||¬«      ƒ d{  –—†  y7 ŒT# t        $ r!}t        j                  d| |«       Y d}~Œwd}~ww xY w7 ŒJ7 Œ6­w)	aÊ  
    Set a Redis-backed spend counter to `value`, mirror it into the short-lived
    spend_db_floor marker `_authoritative_floor_spend` reads, and broadcast both
    to every worker (LIT-3803 pattern: setting, not deleting, means a worker's
    own self-delivered broadcast still carries the reset value forward).

    Without the floor marker, `_authoritative_floor_spend` can re-derive a
    stale, pre-reset value from a marker another worker cached moments earlier
    and raise the just-reset counter right back up via `_repair_stale_spend_counter`.
    Without the broadcast, a worker that already cached the pre-reset key object
    or floor marker keeps enforcing against it until its own TTL expires.
    r   )Ú SPEND_DB_FLOOR_CACHE_TTL_SECONDSrµ  r·  r¸  NzhFailed to update spend counter %s in Redis: %s. Budget checks may use stale value until counter expires.zspend_db_floor:)Ú	cache_keyÚ	new_valuer¹  )r©  r  rµ  r½  r¾  r¿  rÀ  r!  r   rº   r4   )rÄ  ræ   r  rµ  rÅ  Ú	floor_keys         r€   Ú+_set_spend_counter_with_floor_and_broadcastr  9  së   è ø€ ÷ aà×'Ñ'×1Ñ1°kÈÐTVÐ1ÔWØ×&Ñ&Ð2ð	Ø%×1Ñ1×AÑAÀkÐY^ÐdfÐAÓg×gÐgð )¨¨Ð6€IØ×'Ñ'×1Ñ1°iÀuÐRrÐ1Ôsä
)°KÈ5ÐVXÔ
Y×YÐYÜ
)°IÈÐTtÔ
u×uÑuð hùÜò 	Ü ×(Ñ(ðKàØ÷	ñ ûð	úð ZøØuús^   ‚3C¶!B. ÁB,ÁB. Á4CÂCÂCÂ&CÂ'CÂ,B. Â.	CÂ7CÃCÃCÃCÃC.c                 óz   — | syt        | t        «      rt        j                  | «      n| }t	        d„ |D «       «      S )a]  Coerce a key's stored `budget_limits` into a tuple of plain window dicts.

    It is a DB Json column, so a caller reading it straight off `find_unique`
    gets an already-parsed list; one reading it off `json.dumps`'d text (or a
    raw SQL row) gets the string form. Either way each entry is a plain dict,
    except wherever a caller already validated the field through a pydantic
    model (e.g. `UserAPIKeyAuth.budget_limits`), which yields `BudgetLimitEntry`
    objects instead -- coerced here via `model_dump()`, matching
    `_set_budget_reset_at`'s identical coercion in team_endpoints.py.
    r}   c              3   ó`   K  — | ]&  }t        |t        «      r|n|j                  «       –— Œ( y ­wr|   )r¸  rŒ   r‰   )rB  Ú
raw_windows     r€   rD  z(_budget_limit_windows.<locals>.<genexpr>i  s(   è ø€ ÒwÐ]gœz¨*´dÔ;‘À×AVÑAVÓAXÓXÑwùs   ‚,.)r¸  r’   r°  rP  Útuple)rK  rb  s     r€   Ú_budget_limit_windowsr
  [  s7   € ñ ØÜ6@ÀÔPSÔ6TœŸ™ MÔ2ÐZg€KÜÑwÐkvÔwÓwÐwr‚   rd  c                 óê   — | j                  d«      }t        |t        «      r|s| S t        j                  t
        j                  «      t        t        |«      ¬«      z   }i | ¥d|j                  «       i¥S )aã  Restart one budget window from now, by advancing its `reset_at`.

    `window_start` is derived elsewhere as `reset_at - budget_duration`
    (`get_budget_window_start`), so `reset_at` must be set to `now +
    budget_duration` -- a window floating from THIS moment -- to make
    `window_start` land at `now` and exclude the historical spend that
    triggered the block. Reusing `get_budget_reset_time`/
    `ResetBudgetJob._reset_expired_window`'s calendar-standardized boundary
    (e.g. "next midnight") would not do that: for a "1d" window `next
    midnight - 1d` is simply the START of the calendar day already in
    progress, which still covers that spend. That reuse is only safe for the
    scheduled job, which runs right as `reset_at` naturally elapses, so the
    elapsed boundary it computes is already close to "now". A manual reset
    can happen at any point mid-window, so it needs the floating form
    instead. A window with no `budget_duration` is returned unchanged.
    rj  rÉ   rY  )
r¹   r¸  r’   r   rË   r	   rÌ   r   r    rK  )rd  rk  Únew_reset_ats      r€   Ú_advance_one_key_budget_windowr  l  sl   € ð" �z‰zÐ+Ó,€HÜ�h¤Ô$©HØˆÜ"Ÿ,™,¤x§|¡|Ó4´yÔI\Ð]eÓIfÔ7gÑg€LðØ
ðà�L×*Ñ*Ó,ñð r‚   c              ƒ   ó€  K  — t        |«      }|syt        d„ |D «       «      }dt        j                  |t        ¬«      i}t        | «      j                  j                  d|i|¬«      ƒ d{  –—†  |D ]D  }|j                  d«      }t        |t        «      sŒ%|sŒ(d|› d	|› �}t        |d
¬«      ƒ d{  –—†  ŒF y7 ŒN7 Œ	­w)a‚  Force-expire every one of a key's own `budget_limits` windows (extra
    time-windowed caps layered on top of the lifetime max_budget, e.g. a daily
    limit) so a manual spend reset also clears them, not just the lifetime
    counter.

    Persists the advanced `reset_at` boundaries BEFORE zeroing any window's
    Redis counter, not after: a window counter reading zero is only durable
    once every reader recomputing its floor from the DB sees the new
    boundary too (`get_current_spend` re-derives a window counter from real
    `LiteLLM_SpendLogs` rows inside `[window_start, now)` on every read below
    max_budget, see its `is_window` branch). Zeroing first would let a
    request racing the DB write compute `window_start` from the stale
    pre-reset boundary, re-sum the unchanged historical spend, and put the
    counter right back where it was before the write ever landed.
    Nc              3   ó2   K  — | ]  }t        |«      –— Œ y ­wr|   )r  rS  s     r€   rD  z,_reset_key_budget_windows.<locals>.<genexpr>Ÿ  s   è ø€ Ò TÀqÔ!?À×!BÑ Tùs   ‚rK  )r*  rÅ  r   rj  r¶  z:window:r3  ©rÄ  ræ   )r
  r	  r°  r]  r’   rg   r£   r    r¹   r¸  r  )	r¥   rÞ  rK  ÚwindowsÚreset_windowsÚreset_payloadrd  rk  rÄ  s	            r€   Ú_reset_key_budget_windowsr  ‡  sÑ   è ø€ ô( +¨=Ó9€GÙØä Ñ TÈGÔ TÓT€Mð ,¬T¯Z©Z¸ÌsÔ-SÐT€MÜ
% mÓ
4×
:Ñ
:×
AÑ
AØ˜Ð'Øð Bó ÷ ð ð
  ò bˆØ—:‘:Ð/Ó0ˆÜ�h¤Õ$ªØ& ~Ð&6°h¸x¸jÐIˆKÜ=È+Ð]`Ôa×aÑañ	bðøð bús0   ‚A)B>Á+B:Á,*B>ÂB>ÂB>Â2B<Â3B>Â<B>z/key/{key:path}/reset_spendc              ƒ   ó²  K  — 	 ddl m}m}m}m} |€t        t        j                  ddi¬«      ‚d| vr| }n || «      }t        t        |«      «      j                  d|idd	i¬
«      ƒ d {  –—† }	|	€!t        t        j                  dd| › d�i¬«      ‚|	j                  xs d}
t        |j                  |	«      }t        |	|||¬«      ƒ d {  –—†  t        t        |«      «      j!                  d|id|i¬«      ƒ d {  –—† }|€t        t        j                  ddi¬«      ‚d|› �}t#        ||¬«      ƒ d {  –—†  t%        |||	j&                  ¬«      ƒ d {  –—†  t)        |||¬«      ƒ d {  –—†  |j*                  }|j,                  }|||
||dœS 7 �Œ%7 ŒÇ7 Œ˜7 Œa7 ŒC7 Œ/# t
        $ r ‚ t.        $ r&}t1        j2                  d|«       t5        |«      ‚d }~ww xY w­w)Nr   )r*   r¥   r~  rž  rµ   ro  r¶   rì  rÅ  r  Tr  rí  rî  r3  )rÝ  rá   r¥   rž  r¢  r   zFailed to update key spendr¶  r  )r¥   rÞ  rK  r‰  )Úkey_hashr¢  Úprevious_spendrR  rW  zError resetting key spend: %s)r©  r*   r¥   r~  rž  r   r   r9  r¤   rg   ra  rv  r¢  rÿ  rú  rù  r    r  r  rK  r+   rR  rW  r!  r   r?  rZ   )rt  rž   rá   ry  r*   r¥   r~  rž  rÞ  ró  rý  rú  Úupdated_keyÚ_counter_keyrR  rW  r#  s                    r€   Úreset_key_spend_fnr  °  sF  è ø€ ðX+÷	
ó 	
ð Ð ÜÜ"×AÑAØÐ!JÐKôð ð
 �s‰?Ø ‰Ná'¨›_ˆNä"/Ô0KÈMÓ0ZÓ"[×"gÑ"gØ˜NÐ+Ø+¨TÐ2ð #hó #
÷ 
ˆ
ð ÐÜÜ"×5Ñ5Ø 4¨ u¨KÐ!8Ð9ôð ð
  *×/Ñ/Ò6°3ˆÜ5°d·m±mÀZÓPˆä0Ø Ø/Ø'Ø1ô	
÷ 	
ð 	
ô $1Ô1LÈ]Ó1[Ó#\×#cÑ#cØ˜NÐ+Ø˜8Ð$ð $dó $
÷ 
ˆð
 ÐÜÜ"×AÑAØÐ!=Ð>ôð ð !+¨>Ð*:Ð;ˆÜ9ÀlÐZbÔc×cÐcÜ'Ø'Ø)Ø$×2Ñ2ô
÷ 	
ð 	
ô 'Ø'Ø1Ø/ô
÷ 	
ð 	
ð (×2Ñ2ˆ
Ø!,×!<Ñ!<ˆð 'ØØ+Ø$Ø.ñ
ð 	
ðu
ùð	
øð
øð" 	døð	
øð	
ùô  ò ØÜò +Ü×&Ñ&Ð'FÈÔJÜ'¨Ó*Ð*ûð+üs–   ‚G„A&F Á*FÁ+AF Ã
FÃ0F Ã;FÃ<8F Ä4FÄ5F ÅFÅF Å*FÅ+#F ÆGÆF ÆF ÆF ÆF ÆF ÆF ÆGÆ.!GÇGÇGr  c              ƒ   ó  K  — t        | «      ry | j                  €+t        dt        j                  dt
        j                  ¬«      ‚t        t        |«      «      j                  d| j                  iddi¬«      ƒ d {  –—† }|€+t        dt        j                  dt
        j                  ¬«      ‚t        j                  |j                  «       «      }|r:|j                  |k7  r+t        dt        j                  dt
        j                  ¬«      ‚|r9||j                  vr+t        dt        j                  d	t
        j                  ¬«      ‚|r]|j                  �&||j                  D �	cg c]  }	|	j                  ‘Œ c}	vr+t        d
t        j                  dt
        j                  ¬«      ‚|rœ	 t        t!        |«      «      j                  d|i¬«      ƒ d {  –—† }
|
€+t        dt        j                  dt
        j                  ¬«      ‚t%        | ||
¬«      ƒ d {  –—† }|s(t'        t
        j                  d| j(                  › �¬«      ‚|S 7 �ŒËc c}	w 7 Œ{# t"        $ r, t        dt        j                  dt
        j                  ¬«      ‚w xY w7 Œr­w)Nz]You are not authorized to access this endpoint. No 'user_id' is associated with your API key.r�   rÔ   r  Tr  z3You are not authorized to check another user's keysz0You are not authorized to check this team's keysr¿   z8You are not authorized to check this organization's keysr   rÅ  r`  zKey Hash not found.r  r  r,  r¶   )rE   r�   rÝ   rÞ   rß   r   r  r¤   rf   ra  ÚLiteLLM_UserTablerÃ  r‰   r@  r  r   rg   r!  r   r   rã   )rá   r�   r¿   r   rÒ   r  r¥   Úcomplete_user_info_db_objÚcomplete_user_infor  rÌ  Úcan_user_query_key_infos               r€   Úvalidate_key_list_checkr     s«  è ø€ ô Ð-Ô.Øà× Ñ Ð(ÜØsÜ ×2Ñ2ØÜ×*Ñ*ô	
ð 	
ô @MÌ^Ð\iÓMjÓ?k×?wÑ?wØÐ+×3Ñ3Ð4Ø+¨TÐ2ð @xó @÷ :Ðð
 !Ð(ÜØsÜ ×2Ñ2ØÜ×*Ñ*ô	
ð 	
ô !2× @Ñ @ÐAZ×AeÑAeÓAgÓ hÐñ Ø×%Ñ%¨Ò0Ü ØMÜ$×6Ñ6ØÜ×.Ñ.ô	ð ñ ØÐ,×2Ñ2Ñ2Ü ØJÜ$×6Ñ6ØÜ×.Ñ.ô	ð ñ Ø×6Ñ6Ð>À/Ø9K×9dÑ9döZ
Ø+5ˆJ×&Ó&òZ
ñ C
ô !ØRÜ$×6Ñ6Ø'Ü×.Ñ.ô	ð ñ ð	ÜFSÜ+¨MÓ:óGç‰kØ Ð)ð ó ÷AˆHð ÐÜ Ø-Ü$×6Ñ6Ø Ü×.Ñ.ô	ð ô 0HØ/ØØô0
÷ *
Ðñ
 'ÜÜ"×5Ñ5ØRÐSd×SnÑSnÐRoÐpôð ð ÐðY:ûòFZ
ðAùô
 ò 	Ü Ø-Ü$×6Ñ6Ø Ü×.Ñ.ô	ð ð	úð*
ús[   ‚A:JÁ<IÁ=C(JÅ%I
Å81JÆ*)I ÇIÇI Ç>JÈJ	È1JÉ
JÉI É5JÊJr  c              ƒ   ó,  K  — | �| j                   sg S t        dt        |«      j                  j	                  dd| j                   ii¬«      ƒ d{  –—† «      }|€g S |D �cg c]%  }t
        j                  |j                  «       «      ‘Œ' c}S 7 Œ=c c}w ­w)zEFetch team objects for all teams a user belongs to (single DB query).NzSequence[BaseModel] | Noner¿   rå  r`  )r@  r   re   r£   r›   ÚLiteLLM_TeamTablerÃ  r‰   )r  r¥   r@  rb  s       r€   Ú_fetch_user_team_objectsr#  |  s•   è ø€ ð
 Ð!Ð);×)AÒ)AØˆ	ä/3Ø$Ü˜]Ó+×1Ñ1×;Ñ;À9ÈtÐUg×UmÑUmÐNnÐBoÐ;Óp×pó0€Eð €}Øˆ	àLQÖRÀDÔ×,Ñ,¨T¯_©_Ó->Õ?ÒRÐRð 	qúò
 Sùs$   ‚ABÁB
ÁBÁ *BÂ
BÂBÚteam_objectsc                 ó\   — |D �cg c]  }t        | |¬«      sŒ|j                  ‘Œ c}S c c}w )z8Filter team objects to those where the user is an admin.rù  )rB   r¿   ©rá   r$  rb  s      r€   Ú _get_admin_team_ids_from_objectsr'  Ž  s1   € ð ".öØÔ1DÐWhÐswÖ1xˆ�‹òð ùò s   …)˜)c                 ó¦   — |D �cg c]A  }t        | |¬«      s2t        | |t        j                  j                  ¬«      r|j
                  ‘ŒC c}S c c}w )a  Filter team objects to non-admin teams where the caller has /key/list
    permission via team_member_permissions. These teams should grant the
    caller full key visibility (same as a team admin), so other members'
    keys and service account keys (user_id=NULL) are returned.rù  )rá   r”  Ú
permission)rB   rD   r=  ÚKEY_LISTræ   r¿   r&  s      r€   Ú3_get_team_ids_with_key_list_permission_from_objectsr+  ˜  sQ   € ð !ö	àÜ"Ð5FÐQUÕVÜ'Ø/ØÜ*×3Ñ3×9Ñ9õ
ð 	�‹ò	ð 	ùò 	s   …AAc                 ó~   ‡ — |D �cg c],  }t        ˆ fd„|j                  D «       «      r|j                  ‘Œ. c}S c c}w )zCFilter team objects to those where the user is a member (any role).c              3   óp   •K  — | ]-  }|j                   d uxr |j                   ‰j                   k(  –— Œ/ y ­wr|   )r�   )rB  rÅ   rá   s     €r€   rD  z4_get_member_team_ids_from_objects.<locals>.<genexpr>´  s:   øè ø€ ò 
àð �N‰N $Ð&ÒV¨6¯>©>Ð=N×=VÑ=VÑ+VÓVñ
ùs   ƒ36)ÚanyrÄ   r¿   r&  s   `  r€   Ú!_get_member_team_ids_from_objectsr/  ¬  sD   ø€ ð !öàÜó 
à×1Ñ1ô
ô 
ð 	�‹òð ùò s   †1:c              ƒ   óN   K  — t        | |«      ƒ d{  –—† }t        ||«      S 7 Œ­w)z,Get all team IDs where the user is an admin.N)r#  r'  ©r  rá   r¥   r$  s       r€   Úget_admin_team_idsr2  »  s,   è ø€ ô !9Ð9KÈ]Ó [×[€LÜ+Ð,=¸|ÓLÐLð \úó   ‚%’#“%c              ƒ   óN   K  — t        | |«      ƒ d{  –—† }t        ||«      S 7 Œ­w)zÃ
    Get all team IDs where the user is a member (any role, including admin).

    Used to determine which teams' service accounts (keys with user_id=NULL)
    a regular team member can see.
    N)r#  r/  r1  s       r€   Úget_member_team_idsr5  Å  s,   è ø€ ô !9Ð9KÈ]Ó [×[€LÜ,Ð->ÀÓMÐMð \úr3  ÚactiveÚexpiredÚVALID_EXPIRES_FILTER_VALUESz	/key/listrt  zPage number)r$  Úgeé
   z	Page sizeéd   )r$  r9  Úlez�Filter keys by user ID. Exact match by default; set substring_matching=true (admin only) for case-insensitive substring matching.zFilter keys by team IDzFilter keys by organization IDzFilter keys by key hashzƒFilter keys by key alias. Exact match by default; set substring_matching=true (admin only) for case-insensitive substring matching.zReturn full key objectz4Include all keys for teams that user is an admin of.z Include keys created by the userz9Column to sort by (e.g. 'user_id', 'created_at', 'spend')ÚdesczSort order ('asc' or 'desc')z$Expand related objects (e.g. 'user')z!Filter by status (e.g. 'deleted')zFilter keys by project IDzFilter keys by access group IDzFilter keys by agent IDa  If true (proxy admins only), match user_id/key_alias as case-insensitive substrings instead of exact values. Defaults to false: /key/list matched these exactly before substring search was added, and an exact user_id/key_alias filter must never return another user's keys.z¾Filter keys by expiration. 'expired' returns keys whose expires is in the past; 'active' returns keys that never expire or expire in the future. Omit to return keys regardless of expiration.ÚpageÚsizeÚreturn_full_objectÚinclude_team_keysÚinclude_created_by_keysÚsort_byÚ
sort_orderÚexpandr   Úaccess_group_idÚsubstring_matchingrV  c              ƒ   óv  K  — 	 ddl m} t        j                  d«       |€ t        j                  d«       t        d«      ‚|�|dk7  rt        ddd	i¬
«      ‚t        |t        «      r|t        vrt        dddi¬
«      ‚t        |||||||¬«      ƒ d{  –—† }|
s|r#t        ||¬«      ƒ d{  –—† }t        ||¬«      }ng }d}|
r,t        ||¬«      }t        ||¬«      }|rt        h |£|£«      }nd}|j                   t"        j$                  j&                  t"        j(                  j&                  fv }|xr |}|s|s|j*                  }t-        d.i d|“d|“d|“d|“d|“d|“d|“d|	“d|“d|“d|“d|“d|“d|“d|“d|“d|“d |“d!|“d"|“d#t        |t        «      r|nd“Žƒ d{  –—† }t        j                  d$«       |S 7 �Œ/7 �Œ7 Œ!# t
        $ rã}t        j.                  d%|«       t        |t        «      rZt1        t3        |d&d'|› d(�«      t4        j6                  t3        |d)d*«      t3        |d+t8        j:                  j<                  «      ¬,«      ‚t        |t0        «      r|‚t1        d-t        |«      z   t4        j6                  t3        |d)d*«      t8        j:                  j<                  ¬,«      ‚d}~ww xY w­w)/a½  
    List all keys for a given user / team / organization.

    Parameters:
        expand: Optional[List[str]] - Expand related objects (e.g. 'user' to include user information)
        status: Optional[str] - Filter by status. Currently supports "deleted" to query deleted keys.

    Returns:
        {
            "keys": List[str] or List[UserAPIKeyAuth],
            "total_count": int,
            "current_page": int,
            "total_pages": int,
        }

    When expand includes "user", each key object will include a "user" field with the associated user object.
    Note: When expand=user is specified, full key objects are returned regardless of the return_full_object parameter.
    r   r§   zEntering list_keys functionNro  ÚdeletedrÓ   rµ   z<Invalid status value. Currently only 'deleted' is supported.r¶   z6Invalid expires value. Supported: 'active', 'expired'.)rá   r�   r¿   r   rÒ   r  r¥   )r  r¥   )rá   r$  r¥   r>  r?  r�   r¿   rÒ   r  r@  r   Úadmin_team_idsÚmember_team_idsrB  rC  rD  rE  r   r  rF  r7  Úuse_substring_matchingÚexpires_filterzSuccessfully prepared responsezError in list_keys: %sr¸   úerror(rº  r×   r»  r·   rÔ   r¼  r}   )r©  r¥   r   r­  rµ   r!  r   r¸  r’   r8  r   r#  r/  r'  r+  r  rã   rä   rå   ræ   ÚPROXY_ADMIN_VIEW_ONLYr�   Ú_list_key_helperr?  rÝ   r8  rÞ   r  Úfastapir   r9  )r±  rá   r>  r?  r�   r¿   r   r  rÒ   r@  rA  rB  rC  rD  rE  r   r  rF  r7  rG  rV  r¥   r  r$  rK  rJ  Úlist_permission_team_idsr•  rL  r¨  r#  s                                  r€   Ú	list_keysrS  ×  si  è ø€ ð|}
Ý<ä×"Ñ"Ð#@ÔAàÐ Ü ×&Ñ&Ð'?Ô@ÜÐ4Ó5Ð5ð Ð &¨IÒ"5ÜØØÐ!_Ð`ôð ô
 �gœsÔ#¨Ô7RÑ(RÜØØÐ!YÐZôð ô
 +BØ/ØØØ+ØØØ'ô+
÷ %
Ðñ Ñ 7Ü!9Ø#5Ø+ô"÷ ˆLô @Ø"3Ø)ô‰Oð
 ˆLØ"ˆOáÜ=Ø"3Ø)ôˆNô /bØ"3Ø)ô/Ð$ñ (Ü!%Ð&R¨Ð&RÐ9QÐ&RÓ!S‘à!ˆNà 1× ;Ñ ;Ü×(Ñ(×.Ñ.Ü×2Ñ2×8Ñ8ð@
ð !
ˆð );Ò(M¸~Ðñ ™~Ø'×/Ñ/ˆGä 0ò !
Ù'ð!
áð!
ñ ð!
ñ ð	!
ñ
 ð!
ñ  ð!
ñ ð!
ñ  2ð!
ñ ,ð!
ñ *ð!
ñ ,ð!
ñ %<ð!
ñ ð!
ñ "ð!
ñ ð!
ñ  ð!!
ñ" "ð#!
ñ$ ,ð%!
ñ& ð'!
ñ( $:ð)!
ô* '1°¼#Ô&>™7ÀDøð+!
÷ 
ˆô0 	×"Ñ"Ð#CÔDàˆðk%
ùðùð\
ùô8 ò 
Ü×&Ñ&Ð'?ÀÔCÜ�aœÔ'Ü Ü  8¨v°a°S¸¨]Ó;Ü$×:Ñ:Ü˜a ¨&Ó1Ü˜Q ¬w¯~©~×/\Ñ/\Ó]ô	ð ô ˜œ>Ô*ØˆGÜØ,¬s°1«vÑ5Ü ×6Ñ6Ü˜!˜W fÓ-Ü—‘×>Ñ>ô	
ð 	
ûð
üsa   ‚J9„BG
 ÂGÂG
 Â,GÂ-C9G
 Æ&GÆ'G
 ÇJ9ÇG
 ÇG
 ÇG
 Ç
	J6ÇCJ1Ê1J6Ê6J9Úquery_paramsÚwhere_partsc              ƒ   óh  ‡K  — g }| j                   r8‰j                  | j                   «       |j                  dt        ‰«      › �«       g }| j                   rKt        t	        |«      «      j                  d| j                   i¬«      ƒ d{  –—† }|�t        |dg «      xs g }|rRdj                  ˆfd„t        t        |«      «      D «       «      }‰j                  |«       |j                  d|› d	�«       |r%|j                  d
dj                  |«      › d	�«       y|j                  d«       y7 Œ¤­w)z…Append SQL scope conditions so non-admin users only see aliases for
    keys they own or keys belonging to teams they are members of.zuser_id = $r�   r`  Nr@  ú, c              3   óF   •K  — | ]  }d t        ‰«      |z   dz   › �–— Œ y­w)ú$rt  N)r¾  )rB  ÚirT  s     €r€   rD  z/_apply_non_admin_alias_scope.<locals>.<genexpr>¬  s)   øè ø€ Ò,mÐQR¨q´°\Ó1BÀQÑ1FÈÑ1JÐ0KÔ-LÑ,mùs   ƒ!zteam_id IN (rº  ú(z OR ÚFALSE)
r�   r\  r¾  r¤   rf   ra  r8  ÚjoinÚranger  )rá   r¥   rT  rU  Úscope_conditionsÚ
user_teamsr  Úteam_placeholderss     `     r€   Ú_apply_non_admin_alias_scoperb  •  s-  øè ø€ ð *,ÐØ× Ò Ø×ÑÐ-×5Ñ5Ô6Ø×Ñ +¬c°,Ó.?Ð-@Ð AÔBð €JØ× Ò Ü -¬n¸]Ó.KÓ L× XÑ XØÐ/×7Ñ7Ð8ð !Yó !
÷ 
ˆð ÐÜ  ¨7°BÓ7Ò=¸2ˆJáØ#'§9¡9Ó,mÔV[Ô\_Ð`jÓ\kÓVlÔ,mÓ#mÐØ×Ñ˜JÔ'Ø×Ñ ,Ð/@Ð.AÀÐ CÔDáØ×Ñ˜Q˜vŸ{™{Ð+;Ó<Ð=¸QÐ?Õ@ð 	×Ñ˜7Õ#ð
ús   ƒBD2ÂD0ÂB%D2z/key/aliases)r9  r$  é2   )r9  r<  r$  z3Search key aliases (case-insensitive partial match)z-Filter aliases to keys belonging to this teamÚsearchc              ƒ   óÖ  K  — 	 ddl m} t        j                  d«       |€ t        j                  d«       t        d«      ‚t        g}g d¢}| j                  t        j                  j                  t        j                  j                  fv }|st        | |||«      ƒ d{  –—†  |r2|j                  d|› d�«       |j                  dt        |«      › �«       |r.|j                  |«       |j                  d	t        |«      › �«       d
j                  |«      }	d|	› �}
 |j                   j"                  |
g|¢­Ž ƒ d{  –—† }|rt%        |d   d   «      nd}|||dz
  |z  gz   }t        |«      dz
  }t        |«      }d|	› d|› d|› �} |j                   j"                  |g|¢­Ž ƒ d{  –—† }|D �cg c]  }|j'                  d«      sŒ|d   ‘Œ }}|dkD  r| |z   nd}t        j                  d|||||«       |||||dœS 7 �Œc7 ŒÆ7 Œ]c c}w # t
        $ rÏ}t        j(                  d|«       t+        |t,        «      rPt/        t1        |dd|› d�«      t2        j4                  t1        |dd«      t1        |dt6        j8                  «      ¬«      ‚t+        |t.        «      r|‚t/        dt;        |«      z   t2        j4                  t1        |dd«      t6        j8                  ¬«      ‚d}~ww xY w­w)a\  
    Lists key aliases with pagination and optional search.

    Non-admin users only see aliases for keys they own or keys belonging to
    their teams.

    Returns:
        {
            "aliases": List[str],
            "total_count": int,
            "current_page": int,
            "total_pages": int,
            "size": int,
        }
    r   r§   zEntering key_aliases functionNro  )zkey_alias IS NOT NULLzkey_alias != ''z"(team_id IS NULL OR team_id != $1)ú%zkey_alias ILIKE $zteam_id = $z AND z@SELECT COUNT(*) AS count FROM "LiteLLM_VerificationToken" WHERE Úcountrt  z8SELECT key_alias FROM "LiteLLM_VerificationToken" WHERE z ORDER BY key_alias ASC LIMIT $z	 OFFSET $rÒ   zHkey_aliases: page=%s, size=%s, search=%r, total_count=%s, total_pages=%s)r5  Útotal_countÚcurrent_pageÚtotal_pagesr?  zError in key_aliases: %sr¸   rN  rº  r×   r»  r·   rÔ   r¼  )r©  r¥   r   r­  rµ   r!  r   rã   rä   rå   ræ   rO  rb  r\  r¾  r]  r«  Ú	query_rawrü  r¹   r?  r¸  r   rÝ   r8  rÞ   r  r   r9  r’   )rá   r>  r?  rd  r¿   r¥   rT  rU  r•  Ú	where_sqlÚ	count_sqlÚ
count_rowsrh  Úaliases_paramsÚ	limit_idxÚ
offset_idxÚaliases_sqlr#  rí  r5  rj  r#  s                         r€   r   r   ·  s  è ø€ ð8[
Ý<ä×"Ñ"Ð#BÔCàÐ Ü ×&Ñ&Ð'?Ô@ÜÐ4Ó5Ð5ô .FÐ,Fˆò
ˆð !2× ;Ñ ;Ü×(Ñ(×.Ñ.Ü×2Ñ2×8Ñ8ð@
ð !
ˆñ Ü.Ð/@À-ÐQ]Ð_jÓk×kÐkáØ×Ñ ! F 8¨1 Ô.Ø×ÑÐ!2´3°|Ó3DÐ2EÐFÔGáØ×Ñ Ô(Ø×Ñ ¬S°Ó->Ð,?Ð@ÔAà"Ÿ<™<¨Ó4ˆ	à]Ð^gÐ]hÐiˆ	Ø?Y¸}×?OÑ?O×?YÑ?YÐZcÐ?sÐfrÒ?s×9sˆ
Ù<FœS ¨A¡¨wÑ!7Ô8ÈAˆà ,°°t¸a±xÀ4Ñ6GÐ/HÑ HˆÜ˜~Ó.°Ñ2ˆ	Ü Ó/ˆ
ðà�[ðØ �k ¨:¨,ð	8ð 	ð @Z¸}×?OÑ?O×?YÑ?YÐZeÐ?wÐhvÒ?w×9wˆ
ØAKÖ$d¸#ÈsÏwÉwÐWbÕOc S¨Ó%5Ð$dˆÐ$dà8CÀaº ˜|¨tÑ3Ñ4ÈQˆÜ×"Ñ"ØVØØØØØô	
ð Ø&Ø Ø&Øñ
ð 	
ðO lùð :tøð :xúÚ$døô( ò 
Ü×&Ñ&Ð'AÀ1ÔEÜ�aœÔ'Ü Ü  8¨v°a°S¸¨]Ó;Ü$×:Ñ:Ü˜a ¨&Ó1Ü˜Q ¬v×/TÑ/TÓUô	ð ô ˜œ>Ô*ØˆGÜØ,¬s°1«vÑ5Ü ×6Ñ6Ü˜!˜W fÓ-Ü×6Ñ6ô	
ð 	
ûð
üsz   ‚K)„BH ÂHÂ BH Ä>HÄ?A*H Æ)HÆ*H Æ2H	Ç	H	Ç1H ÈK)ÈH ÈH ÈH È	H È	K&ÈC
K!Ë!K&Ë&K)c                 óÊ   — i }| €y g d¢}| |vr!t        ddddj                  |«      › �i¬«      ‚|j                  «       dvrt        dddi¬«      ‚|j                  «       || <   |S )	N)r¢  rR  rK  rL  rÅ  rÒ   rÓ   rµ   z%Invalid sort column. Must be one of: rW  r¶   )râ  r=  z+Invalid sort order. Must be 'asc' or 'desc')r   r]  Úlower)rC  rD  Úorder_byÚvalid_columnss       r€   Ú_validate_sort_paramsrw  1  s�   € Ø&(€Hà€Øò€Mð �mÑ#ÜØØÐDÀTÇYÁYÈ}ÓE]ÐD^Ð_Ð`ô
ð 	
ð ×ÑÓ Ñ0ÜØØÐJÐKô
ð 	
ð
 #×(Ñ(Ó*€HˆWÑà€Or‚   rM  rË   c                 ó@   — | dk(  rdddd iidd|iigiS ddd idd|iigiS )Nr7  rá  rV  ÚnotÚltrÞ  Úgter}   )rM  rË   s     r€   Ú_build_expires_where_clauser|  Q  sJ   € Ø˜Ò"Ø˜ U¨D MÐ2°YÀÀsÀÐ4LÐMÐNÐNØ�I˜tÐ$ y°5¸#°,Ð&?Ð@ÐAÐAr‚   Úexclude_team_idrJ  rK  rL  c                 ó”  — i }|j                  t        «       «       g }i }| r t        | t        «      r|r	| ddœ|d<   n| |d<   |rt        |t        «      rd|i|d<   |rt        |t        «      r||d<   |r|j	                  |«       |rU| rS|�>|r"|j	                  dd	| id
dd|iiddigigi«       n-|j	                  dd	| iddigi«       n|j	                  d	| i«       |r|j	                  dd|ii«       |r5|D �cg c]  }||xs g vsŒ|‘Œ }}|r|j	                  ddd|iiddigi«       t        |«      dkD  r	d|d
|igi}n"t        |«      dk(  r|j                  |d   «       g |rt        |t        «      r|rd|ddœind|ifnd¢|rt        |t        «      rd|ifnd¢|rt        |t        «      rd|ifnd¢|	rd|	ifnd¢|
rdd|
giifnd¢|rt        |t        «      rd|ifnd¢|�6|t        v r.t        |t        j                  t        j                  «      «      fnd¢­}|rd|g|¢in|}t        j                  d|«       |S c c}w )a  Build filter conditions for key listing.

    Visibility rules:
    - Users always see their own keys (user_id match)
    - Team admins see ALL keys for their admin teams (via admin_team_ids)
    - Regular team members see only service accounts (user_id=NULL) for their
      teams (via member_team_ids). This prevents leaking other members' spend data.
    - created_by visibility is scoped to teams the user currently belongs to,
      so former members cannot see service accounts they created after leaving.
    Úinsensitive)ÚcontainsÚmoder�   ry  r¿   r   Nrá  rˆ  rÞ  rå  rt  r   rÒ   r}   rÅ  r  r  ÚhasSomer7  zFilter conditions: %s)r    Ú._get_condition_to_filter_out_ui_session_tokensr¸  r’   r\  r¾  r8  r|  r   rË   r	   rÌ   r   r­  )r�   r¿   r   rÒ   r  r}  rJ  rK  rB  r  rF  r7  rL  rM  r�   Úor_conditionsÚuser_conditionÚtidÚmember_only_team_idsÚglobal_filtersÚcombined_wheres                        r€   Ú_build_key_filter_conditionsrŠ  W  s%  € ð6  "€EØ	‡L�LÔ?ÓAÔBð 57€Mð 02€NÙ”:˜g¤sÔ+Ù!à#Ø%ñ)ˆN˜9Ò%ð
 )0ˆN˜9Ñ%Ùœ: o´sÔ;Ø%*¨OÐ$<ˆ�yÑ!Ùœ: o´sÔ;Ø,;ˆÐ(Ñ)áØ×Ñ˜^Ô,ñ ¡7ØÐ&Ùð ×$Ñ$àØ)¨7Ð3à $Ø%.°°Ð0GÐ$HØ%.°Ð$5ð'"ðð ð
õð ×$Ñ$ e¨|¸WÐ.EÈ	ÐSWÐGXÐ-YÐ%ZÕ[ð × Ñ  ,°Ð!8Ô9ñ Ø×Ñ˜i¨$°Ð)?Ð@ÔAñ à6EÖ&k¨sÈÐUcÒUiÐgiÒIj¢sÐ&kÐÐ&kÙØ× Ñ àØ" TÐ+?Ð$@ÐAØ" DÐ)ððôô ˆ=Ó˜AÒØ˜  }Ð 5Ð6Ð7‰Ü	ˆ]Ó	˜qÒ	 Ø�‰�] 1Ñ%Ô&ð<ñ œZ¨	´3Ô7ñ *ð ¨9¸mÑLÑMà! 9Ð-ñð ð<ñ %-´¸HÄcÔ1JˆG�XÐÑ
 ÐPRð<ñ &-´¸GÄSÔ1IˆI�wÐÑ
!Èrð<ñ ,6ˆL˜*Ð%Ñ
'¸2ð<ñ FUÐ ¨_Ð,=Ð >Ð?Ñ
AÐZ\ð<ñ (0´J¸xÌÔ4MˆJ˜Ð!Ñ
#ÐSUð<ð" Ð)¨nÔ@[Ñ.[ô )¨¼¿¹ÄhÇlÁlÓ9SÓTÑVàñ%<€Nñ* Xf°5¸5Ð:RÀ>Ð:RÑ2SÐkp€NÜ×ÑÐ6¸ÔGØÐùòU 'ls   Ã9IÄIc              ƒ   óà  K  — t        |||||||
|||||||¬«      }|dz
  |z  }t        j                  d||«       |�t        |t        «      rt        ||«      nd}|dk(  }|r;t        | «      j                  j                  ||||r|nddiddig¬	«      ƒ d{  –—† }n=t        | «      j                  j                  ||||r|nddiddigd
di¬«      ƒ d{  –—† }t        j                  dt        |«      «       |r$t        | «      j                  |¬«      ƒ d{  –—† }n,t        t        | «      «      j                  |¬«      ƒ d{  –—† }t        j                  d|«       | |z   }t        t        dz  t        f   «       }|rªd|v r¦|D �cg c]  }|j                   sŒ|j                   ‘Œ }}|D �cg c]  }|j"                  sŒ|j"                  ‘Œ } }t%        t'        || z   «      «      }!|!rAt)        | «      j                  dd|!ii¬«      ƒ d{  –—† }"|"D �#ci c]  }#|#j                   |#“Œ }}#g }$|D �]8  }	 |j+                  «       }%|st/        |%| «      ƒ d{  –—† }%|r�d|v r‹|j                   r/|j                   |v r!	 ||j                      j+                  «       |%d<   |j"                  rD|j"                  |v r6||j"                     }&|&j                   |&j0                  |&j2                  dœ|%d<   |	du s|rGd|v rC|r%|$j5                  t6        j9                  |%«      «       Œí|$j5                  t;        di |%¤Ž«       �Œ	|%j=                  d«      }'|$j5                  t?        t        |'«      «       �Œ; tA        |$|||¬«      S 7 �Œæ7 �Œ«7 �Œj7 �Œ@c c}w c c}w 7 �Œ„c c}#w # t,        $ r |j                  «       }%Y �Œpw xY w7 �Œc# t,        $ r$ ||j                      j                  «       |%d<   Y �ŒLw xY w­w)a8  
    Helper function to list keys
    Args:
        page: int
        size: int
        user_id: Optional[str]
        team_id: Optional[str]
        key_alias: Optional[str]
        exclude_team_id: Optional[str] # exclude a specific team_id
        return_full_object: bool # when true, will return UserAPIKeyAuth objects instead of just the token
        admin_team_ids: Optional[List[str]] # list of team IDs where the user is an admin
        member_team_ids: Optional[List[str]] # list of team IDs where user is a member (for service account visibility)

    Returns:
        KeyListResponseObject
        {
            "keys": List[str] or List[UserAPIKeyAuth],  # Updated to reflect possible return types
            "total_count": int,
            "current_page": int,
            "total_pages": int,
        }
    )r�   r¿   r   rÒ   r  r}  rJ  rK  rB  r  rF  r7  rL  rM  rt  zPagination: skip=%s, take=%sNrI  rK  r=  rÅ  )r�   Úskiprs  rã  r  T)r�   rŒ  rs  rã  r  zFetched %s keysr`  zTotal count of keys: %sr   r�   rå  )r�   r„   r‡   Úcreated_by_user)rÜ  rh  ri  rj  r}   )!rŠ  r   r­  r¸  r’   rw  rc   r£   r›   rg   r¾  r¨   rg  r¤   rŒ   ry   r�   rˆ  r  r9  r¬   r‰   r!  rN   r„   r‡   r\  r�  rÃ  ÚUserAPIKeyAuthr¹   r   ÚKeyListResponseObject)(r¥   r>  r?  r�   r¿   r   rÒ   r  r}  r@  rJ  rK  rB  rC  rD  rE  r   r  rF  r7  rL  rM  r�   rŒ  ru  Úuse_deleted_tablerÜ  rh  rj  Úuser_maprt  Úuser_idsÚcreated_by_idsÚall_idsÚusersr   Úkey_listÚkey_dictr�  Ú_tokens(                                           r€   rP  rP  Ù  sC  è ø€ ô^ 0ØØØ'ØØØ'Ø%Ø'Ø 7ØØ'ØØ5Ø%ô€Eð$ ˜!‘8˜tÑ#€Dä×ÑÐ=¸tÀTÔJð 7>Ð6IÌjÐY`ÔbeÔNfÔ˜g zÔ2Ðlpð ð
  &¨Ñ2Ðñ Ü7¸ÓF×LÑL×VÑVØØØñ ñ ð " 6Ð*Ø˜fÐ%ðð Wó 
÷ 
‰ô 1°Ó?×EÑE×OÑOØØØñ ñ ð " 6Ð*Ø˜fÐ%ðð
 )¨$Ð/ð Pó 
÷ 
ˆô ×ÑÐ0´#°d³)Ô<ñ Ü=¸mÓL×RÑRÐY^ÐRÓ_×_‰ä)Ô*EÀmÓ*TÓU×[Ñ[ÐbgÐ[Óh×hˆä×ÑÐ8¸+ÔFð (˜<¨4Ñ/Ð0€Kô ”C˜$‘J¤Ð,Ñ-Ó/€HÙ�&˜FÑ"Ø26ÖF¨3¸#¿+»+˜3Ÿ;›;ÐFˆÐFØ;?Ö R°CÀ3Ç>Ã> §£Ð RˆÐ RÜœc (¨^Ñ";Ó<Ó=ˆÙÜ9DÀ]Ó9S×9]Ñ9]Ø  4¨ /Ð2ð :^ó :÷ 4ˆEð 8=Ö=¨t˜Ÿ™ dÑ*Ð=ˆHÐ=ð VX€HØó $/ˆð	"Ø—~‘~Ó'ˆHñ
 !Ü=¸hÈÓV×VˆHñ �f Ñ&Ø�{Š{˜sŸ{™{¨hÑ6ðDØ'/°·±Ñ'<×'GÑ'GÓ'I�H˜VÑ$ð �~Š~ #§.¡.°HÑ"<Ø"*¨3¯>©>Ñ":�à.×6Ñ6Ø"1×"<Ñ"<Ø"1×"<Ñ"<ñ/�Ð*Ñ+ð  Ñ%©&°V¸vÑ5EÙ à—‘Ô @× OÑ OÐPXÓ YÕZà—‘Ü"Ñ. XÑ.öð —\‘\ 'Ó*ˆFØ�O‰OœD¤ fÓ-Ö.ðI$/ôL !ØØØØô	ð ð}
ùð
ùð& `ùàhûò GùÚ Rð4ûò >øô ò 	"à—x‘x“z‹Hð	"úð
 Wúô !ò DØ'/°·±Ñ'<×'AÑ'AÓ'C�H˜VÔ$ðDüsç   ‚BO.ÂM=Â=O.ÃN ÃAO.ÄNÄ,O.ÅNÅAO.ÆN	ÆN	Æ,O.Æ2NÇNÇ=O.ÈNÈO.ÈNÈ,
O.È7NÉO.ÉN;É$O.É> N>ÊC O.Î O.ÎO.ÎO.Î	O.ÎO.ÎN8Î4O.Î7N8Î8O.Î>)O+Ï'O.Ï*O+Ï+O.c                  ó"   — dddiddt         iigiS )z3
    Condition to filter out UI session tokens
    rÞ  r¿   Nry  )r   r}   r‚   r€   rƒ  rƒ  �  s,   € ð
 	Ø˜ÐØ˜Ô 8Ð9Ð:ð
ðð r‚   rx  c           
   ƒ   óè  K  — | j                   t        j                  j                  k(  ryt	        t        |«      «      j                  d|i¬«      ƒ d{  –—† }|€t        ddd|› �i¬«      ‚|j                  rGt        |j                  ||d¬	«      ƒ d{  –—† }|�$t        | |¬
«      ryt        | |¬
«      ƒ d{  –—† ryt        ddd|› d| j                   › d| j                  › �i¬«      ‚7 Œ—7 ŒX7 Œ5­w)a  
    Check that the caller has admin privileges for the target key.

    Allowed callers:
    - Proxy admin
    - Team admin for the key's team
    - Org admin for the key's team's organization

    Raises HTTPException(403) if the caller is not authorized.
    NrÅ  r`  r  rµ   zKey not found: r¶   Trƒ  rù  r´   z7Only proxy admins, team admins, or org admins can call z. user_role=z
, user_id=)rã   rä   rå   ræ   r¤   rg   ra  r   r¿   r/   rB   rA   r�   )rá   rx  r¥   rž  rì   Útarget_key_rowr”  s          r€   r£  r£  ™  s,  è ø€ ð$ ×"Ñ"Ô&6×&BÑ&B×&HÑ&HÒHØô #0Ô0KÈMÓ0ZÓ"[×"gÑ"gØ˜Ð%ð #hó #÷ €Nð ÐÜØØ˜¨|¨nÐ=Ð>ô
ð 	
ð ×ÒÜ /Ø"×*Ñ*Ø'Ø1Øô	!
÷ 
ˆð ÐÜ"Ð5FÐQYÕZØÜ0ÐCTÐ_gÔh×hÐhØä
ØàÐNÈuÈgð VØ*×4Ñ4Ð5°ZÐ@Q×@YÑ@YÐ?Zð\ð
ôð ð/øð
øð iús7   ‚AC2ÁC,ÁA C2ÂC.Â$C2Â:C0Â;2C2Ã.C2Ã0C2ú
/key/blockÚhttp_requestc              ƒ   óZ  K  — ddl m}m} ddlm}m}m}m}	m}
m	} |	€$t        t        j                  j                  › «      ‚t        | j                  «      s+t!        dt"        j$                  dt&        j(                  ¬«      ‚| j                  j+                  d«      r || j                  ¬	«      }n| j                  }t-        |||	|d
¬«      ƒ d{  –—†  t/        t1        |	«      «      j3                  d|i¬«      ƒ d{  –—† }|€+t!        dt"        j4                  dt&        j6                  ¬«      ‚ |«       r™t9        j:                   |t=        t?        tA        jB                  «       «      tE        jF                  tH        jJ                  «       ||||¬«      |jL                  tN        jP                  |dd|jS                  «       ¬«	      ¬«      «       t/        t1        |	«      «      jU                  d|itW        ddi«      ¬«      ƒ d{  –—† }tY        |||
¬«      ƒ d{  –—†  |S 7 �ŒR7 �Œ'7 Œ"7 Œ­w)a  
    Block an Virtual key from making any requests.

    Parameters:
    - key: str - The key to block. Can be either the unhashed key (sk-...) or the hashed key value

     Example:
    ```bash
    curl --location 'http://0.0.0.0:4000/key/block'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "key": "sk-Fn8Ej39NxjAXrvpUGKghGw"
    }'
    ```

    Note: This is an admin-only endpoint. Only proxy admins, team admins, or org admins can block keys.
    r   ©Úget_audit_log_changed_byÚis_audit_logging_enabled©Úcreate_audit_log_for_updater*   r{  r¥   r~  rž  NúInvalid key format.rt  rÔ   r˜  rp  rœ  r¡  rÅ  r`  rq  ©ry  rá   r{  rß  ú{}©	r€  rL  Ú
changed_byÚchanged_by_api_keyr§  Ú	object_idÚactionÚupdated_valuesÚbefore_value©Úrequest_dataTr   r‰  ©-Ú+litellm.proxy.management_helpers.audit_logsr   r¡  r©  r£  r*   r{  r¥   r~  rž  r!  r¶  r:  ræ   r[   rt  rÝ   rÞ   rß   r   rw  r½  r£  r¤   rg   ra  ru  rv  rÆ  rÇ  ÚLiteLLM_AuditLogsr’   r   Úuuid4r   rË   r	   rÌ   r-  ÚLitellmTableNamesÚKEY_TABLE_NAMEÚmodel_dump_jsonr    rL   r+   ©rž   r�  rá   ry  r   r¡  r£  r*   r{  r¥   r~  rž  rx  Úexisting_recordr…  s                  r€   Ú	block_keyr¹  Ï  s  è ø€ ÷:÷÷ ð ÐÜÔ,×CÑC×IÑIÐJÓLÐLä˜DŸH™HÔ%ÜØ)Ü ×2Ñ2ØÜ×,Ñ,ô	
ð 	
ð ‡x�x×Ñ˜5Ô!Ù!¨¯©Ô1‰à—x‘xˆô "Ø+Ø!Ø#Ø-Øô÷ ð ô $1Ô1LÈ]Ó1[Ó#\×#hÑ#hØ˜Ð%ð $ió $÷ €Oð ÐÜØ$Ü ×0Ñ0ØÜ×*Ñ*ô	
ð 	
ñ  Ô!Ü×ÑÙ'Ü.Üœ4Ÿ:™:›<Ó(Ü'Ÿ|™|¬H¯L©LÓ9Ù7Ø+=Ø*;Ø1Iô ð
 (9×'@Ñ'@Ü0×?Ñ?Ø*Ø$Ø#'Ø!0×!@Ñ!@Ó!Bôôô	
ô( (Ô(CÀMÓ(RÓS×ZÑZØ˜Ð%Ü% y°$Ð&7Ó8ð [ó ÷ €Fô #Ø!Ø-Ø+ô÷ ð ð €Mðkùðùð@øðúóI   ‚CH+ÃH!Ã-H+Ã=H$Ã>DH+ÈH'ÈH+ÈH)ÈH+È$H+È'H+È)H+ú/key/unblockc              ƒ   óZ  K  — ddl m}m} ddlm}m}m}m}	m}
m	} |	€$t        t        j                  j                  › «      ‚t        | j                  «      s+t!        dt"        j$                  dt&        j(                  ¬«      ‚| j                  j+                  d«      r || j                  ¬	«      }n| j                  }t-        |||	|d
¬«      ƒ d{  –—†  t/        t1        |	«      «      j3                  d|i¬«      ƒ d{  –—† }|€+t!        dt"        j4                  dt&        j6                  ¬«      ‚ |«       r™t9        j:                   |t=        t?        tA        jB                  «       «      tE        jF                  tH        jJ                  «       ||||¬«      |jL                  tN        jP                  |dd|jS                  «       ¬«	      ¬«      «       t/        t1        |	«      «      jU                  d|itW        ddi«      ¬«      ƒ d{  –—† }tY        |||
¬«      ƒ d{  –—†  |S 7 �ŒR7 �Œ'7 Œ"7 Œ­w)a  
    Unblock a Virtual key to allow it to make requests again.

    Parameters:
    - key: str - The key to unblock. Can be either the unhashed key (sk-...) or the hashed key value

    Example:
    ```bash
    curl --location 'http://0.0.0.0:4000/key/unblock'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "key": "sk-Fn8Ej39NxjAXrvpUGKghGw"
    }'
    ```

    Note: This is an admin-only endpoint. Only proxy admins, team admins, or org admins can unblock keys.
    r   rŸ  r¢  Nr¤  rt  rÔ   r˜  rp  r»  r¡  rÅ  r`  rq  r¥  Ú	unblockedr¦  r§  r®  rß  Fr   r‰  r°  r·  s                  r€   Úunblock_keyr¾  A  s  è ø€ ÷:÷÷ ð ÐÜÔ,×CÑC×IÑIÐJÓLÐLä˜DŸH™HÔ%ÜØ)Ü ×2Ñ2ØÜ×,Ñ,ô	
ð 	
ð ‡x�x×Ñ˜5Ô!Ù!¨¯©Ô1‰à—x‘xˆô "Ø+Ø!Ø#Ø-Øô÷ ð ô $1Ô1LÈ]Ó1[Ó#\×#hÑ#hØ˜Ð%ð $ió $÷ €Oð ÐÜØ$Ü ×0Ñ0ØÜ×*Ñ*ô	
ð 	
ñ  Ô!Ü×ÑÙ'Ü.Üœ4Ÿ:™:›<Ó(Ü'Ÿ|™|¬H¯L©LÓ9Ù7Ø+=Ø*;Ø1Iô ð
 (9×'@Ñ'@Ü0×?Ñ?Ø*Ø&Ø#'Ø!0×!@Ñ!@Ó!Bôôô	
ô( (Ô(CÀMÓ(RÓS×ZÑZØ˜Ð%Ü% y°%Ð&8Ó9ð [ó ÷ €Fô #Ø!Ø-Ø+ô÷ ð ð €Mðkùðùð@øðúrº  z/key/healthc           
   ƒ   óx  K  — 	 |j                   }t        dd¬«      }|rDd|v r@t        || t        |«      d   ¬«      ƒ d{  –—† }||d<   |j	                  d«      dk(  rd|d	<   t        di |¤ŽS 7 Œ-# t
        $ r>}t        d
|› �t        j                  t        |dd«      t        j                  ¬«      ‚d}~ww xY w­w)aS  
    Check the health of the key

    Checks:
    - If key based logging is configured correctly - sends a test log

    Usage 

    Pass the key in the request header

    ```bash
    curl -X POST "http://localhost:4000/key/health"      -H "Authorization: Bearer sk-1234"      -H "Content-Type: application/json"
    ```

    Response when logging callbacks are setup correctly:

    ```json
    {
      "key": "healthy",
      "logging_callbacks": {
        "callbacks": [
          "gcs_bucket"
        ],
        "status": "healthy",
        "details": "No logger exceptions triggered, system is healthy. Manually check if logs were sent to ['gcs_bucket']"
      }
    }
    ```


    Response when logging callbacks are not setup correctly:
    ```json
    {
      "key": "unhealthy",
      "logging_callbacks": {
        "callbacks": [
          "gcs_bucket"
        ],
        "status": "unhealthy",
        "details": "Logger exceptions triggered, system is unhealthy: Failed to load vertex credentials. Check to see if credentials containing partial/invalid information."
      }
    }
    ```
    ÚhealthyN)rt  Úlogging_callbacksÚlogging)rá   r±  Úkey_loggingrÁ  r   Ú	unhealthyrt  zKey health check failed: r×   r»  rÔ   r}   )r  ÚKeyHealthResponseÚtest_key_loggingr6   r¹   r!  rÝ   rÞ   r  r8  r   r9  )r±  rá   Úkey_metadataÚhealth_statusÚlogging_statusesr#  s         r€   Ú
key_healthrÊ  ³  sÜ   è ø€ ðr
à/×8Ñ8ˆä2CØØ"ô3
ˆñ ˜I¨Ñ5Ü,<Ø"3ØÜ1°,Ó?À	ÑJô-÷ 'Ðð
 2BˆMÐ-Ñ.ð  ×#Ñ# HÓ-°Ò<Ø'2�˜eÑ$ä Ñ1 =Ñ1Ð1ð'ùô ò 
ÜØ/°¨sÐ3Ü ×6Ñ6Ü˜!˜W fÓ-Ü×6Ñ6ô	
ð 	
ûð
üs:   ‚B:„<A0 Á A.Á,A0 Á-B:Á.A0 Á0	B7Á99B2Â2B7Â7B:c              ƒ   ó<  K  — | j                   t        j                  j                  k(  sn| j                   t        j                  j                  k(  sG| j
                  |k(  s8|j                  | j                  k(  st        j                  | |¬«      ƒ d{  –—† ryy7 Œ­w)zB
    Helper to check if the user has access to the key's info
    )rá   r4  NTF)	rã   rä   rå   ræ   rO  r-  r�   rS   Úuser_belongs_to_keys_teamr  s      r€   r   r     sŒ   è ø€ ð ×'Ñ'Ô+;×+GÑ+G×+MÑ+MÒMØ ×*Ñ*Ô.>×.TÑ.T×.ZÑ.ZÒZà×$Ñ$¨Ò+Ø×ÑÐ0×8Ñ8Ò8Ü+×EÑEØ/Ø%ô
÷ 
ð 
ð
 Øð
ús   ‚BBÂBÂBrÃ  c              ƒ   óö  K  — ddl }ddlm} ddlm} ddlm}m} g }|D ]2  }	|	j                  d«      �|j                  |	d   «       Œ)t        d«      ‚  |«       }
|j                  |
«      }|j                  |j                  «       |j                  «       }|j                  |«       	 dd	d
dœgdœ} ||| |||¬«      ƒ d{  –—† }d|d<   t!        j"                  di |¤Žƒ d{  –—†  t)        j*                  d«      ƒ d{  –—†  |
j-                  «       }|j/                  |«       |rt'        |dd|› �¬«      S t'        |dd|› d�¬«      S 7 Œ‰7 Œi# t$        $ r}t'        |dd|› �¬«      cY d}~S d}~ww xY w7 Œu­w)a3  
    Test the key-based logging

    - Test that key logging is correctly formatted and all args are passed correctly
    - Make a mock completion call -> user can check if it's correctly logged
    - Check if any logger.exceptions were triggered -> if they were then returns it to the user client side
    r   N)ÚStringIO)Úadd_litellm_data_to_request)Úgeneral_settingsr•  Úcallback_namez(callback_name is required in key_loggingzopenai/litellm-key-health-testr   zQHello, this is a test from litellm /key/health. No LLM API call was made for this)ró   Úcontent)rî  Úmessages)rž   rá   r•  rÐ  r±  ztest responseÚmock_responserÄ  zLogging test failed: )Ú	callbacksr   Údetailsrr  z2Logger exceptions triggered, system is unhealthy: rÀ  zWNo logger exceptions triggered, system is healthy. Manually check if logs were sent to ú r}   )rÂ  ÚiorÎ  Ú$litellm.proxy.litellm_pre_call_utilsrÏ  r©  rÐ  r•  r¹   r\  rµ  ÚStreamHandlerÚsetLevelÚERRORÚ	getLoggerÚ
addHandlerrÚ   Úacompletionr!  ÚLoggingCallbackStatusrÆ  ÚsleepÚgetvalueÚremoveHandler)rá   r±  rÃ  rÂ  rÎ  rÏ  rÐ  r•  rÁ  ÚcallbackÚlog_capture_stringÚchÚloggerrž   r#  Úlog_contentss                   r€   rÆ  rÆ  %  sÂ  è ø€ ó ÝåPßIà*,ÐØò IˆØ�<‰<˜Ó(Ð4Ø×$Ñ$ X¨oÑ%>Õ?äÐGÓHÐHð	Iñ !)£
ÐØ×%Ñ%Ð&8Ó9€BØ‡K�K�—‘ÔØ×%Ñ%Ó'€FØ
×Ñ�bÔð
à5ð #Ørñðñ
ˆñ 1ØØ/Ø%Ø-Øô
÷ 
ˆð !0ˆˆ_ÑÜ×!Ñ!Ñ) DÑ)×)Ð)ô �-‰-˜Ó
×Ðð -×5Ñ5Ó7€LØ
×Ñ˜ÔÙÜ$Ø'ØØHÈÈÐWô
ð 	
ô %Ø'ØØmÐnð  nAð  ABð  Cô
ð 	
ð9
øð 	*ùÜò 
Ü$Ø'ØØ+¨A¨3Ð/ô
õ 	
ûð
úð úsg   ‚B&E9Â)E ÃEÃ!E Ã$EÃ%E Ã)E9ÄE7ÄA
E9ÅE ÅE Å	E4ÅE/Å)E4Å*E9Å/E4Å4E9z1^[a-zA-Z0-9][a-zA-Z0-9_\-/\.@]{0,253}[a-zA-Z0-9]$Ú_KEY_ALIAS_PATTERNc                 óü   — | €y	 t        | «       t
        j                  syt        j                  | «      st        dt        j                  dd¬«      ‚y# t        $ r t        dt        j                  dd¬«      ‚w xY w)u(  
    Validate the format of the key_alias.

    A baseline validation always runs, regardless of
    ``litellm.enable_key_alias_format_validation``.

    The remaining charset/length rules are gated behind
    ``litellm.enable_key_alias_format_validation`` (default **False**). When disabled,
    only the baseline validation above is performed, so existing workflows are not
    broken.

    Rules (when enabled):
    - None is OK (no alias).
    - Otherwise must be 2â€“255 chars
    - start/end with alphanumeric
    - only allow a-zA-Z0-9_-/.@
    NzInvalid key_aliasrÒ   rÓ   rÔ   zqInvalid key_alias format. Must be 2-255 characters, start/end with alphanumeric, and only contain a-zA-Z0-9_-/.@.)	ri   rµ  rÝ   rÞ   rß   rÚ   Ú"enable_key_alias_format_validationré  Úmatchr—  s    r€   r»  r»  t  s�   € ð$ ÐØð
Ü# IÔ.ô ×5Ò5Øä×#Ñ# IÔ.Üð HÜ ×2Ñ2ØØô	
ð 	
ð /øô ò 
ÜØ'Ü ×2Ñ2ØØô	
ð 	
ð
ús   …A Á'A;r³  c              ƒ   óð   K  — | �n|�kd| i}|rd|i|d<   t        t        |«      «      j                  |¬«      ƒ d{  –—† }|�/t        d| › d�t        j
                  dt        j                  ¬«      ‚yyy7 Œ8­w)	a(  
    Helper to enforce unique key aliases across all keys.

    Args:
        key_alias (Optional[str]): The key alias to check
        prisma_client (Any): Prisma client instance
        existing_key_token (Optional[str]): ID of existing key being updated, to exclude from uniqueness check
            (The Admin UI passes key_alias, in all Edit key requests. So we need to be sure that if we find a key with the same alias, it's not the same key we're updating)

    Raises:
        ProxyException: If key alias already exists on a different key
    NrÒ   rÅ  ÚNOTr`  zKey with alias 'zB' already exists. Unique key aliases across all keys are required.rÔ   )r¤   rg   Ú
find_firstrÝ   rÞ   rß   r   rw  )rÒ   r¥   r³  Úwhere_clauseÚexisting_keys        r€   r¼  r¼  Ÿ  sš   è ø€ ð" Ð Ð!:Ø2=¸yÐ1IˆÙà#*Ð,>Ð"?ˆL˜Ñä*Ô+FÀ}Ó+UÓV×aÑaÐhtÐaÓu×uˆØÐ#Ü Ø*¨9¨+Ð5wÐxÜ$×6Ñ6Ø!Ü×0Ñ0ô	ð ð $ð ";Ðð vús   ‚9A6»A4¼9A6c                 ó®  — 	 | €yt        | «      dk(  ry| � ddlm}m} |dur"t	        d|j
                  j                  › �«      ‚| j                  «       D ]^  \  }}t        |t        «      sJ ‚t        |d«      r|j                  «       n
t        |«      }d|v rt        |d   «      |d<   t        d
i |¤Ž Œ` yy# t        $ r}t	        d|› d	�«      ‚d}~ww xY w)zÆ
    Validate the model_max_budget is GenericBudgetConfigType + enforce user has an enterprise license

    Raises:
        Exception: If model_max_budget is not a valid GenericBudgetConfigType
    Nr   )r¶  r  Tz=You must have an enterprise license to set model_max_budget. r‰   Úbudget_limitzInvalid model_max_budget: zM. Example of valid model_max_budget: https://docs.litellm.ai/docs/proxy/usersr}   )r¾  r©  r¶  r  rµ  r·  ræ   r¹  r¸  r’   r“  r‰   rŒ   rr  rq   r!  )r…  r¶  r  Ú_modelÚ_budget_infoÚ_infor#  s          r€   r_  r_  À  s   € ð
ØÐ#ØÜÐÓ  AÒ%ØØÐ'ßRà 4Ñ'Ü ØSÐTe×TvÑTv×T|ÑT|ÐS}Ð~óð ð )9×(>Ñ(>Ó(@ò &Ñ$�˜Ü! &¬#Ô.Ð.Ð.ô 6=¸\È<Ô5X˜×/Ñ/Ô1Ô^bÐcoÓ^p�à! UÑ*Ü,1°%¸Ñ2GÓ,H�E˜.Ñ)ÜÑ%˜uÓ%ñ&ð (øô  ò 
ÜØ(¨¨Ð+xÐyó
ð 	
ûð
ús"   ‚B7 …B7 ”B!B7 Â7	CÃ CÃCr|   )T)NN)NFNNNFN)NFNNFNr=  NNNNNFN(P  r�   rÆ  rI  r;  r°  rP  rÖ  ÚrerM  rT  Úcollections.abcr   r   r   r   r   r   r	   Útypingr
   r   r   r   r   r   r   r   rQ  rQ  r   r   r   r   r   r   r   rÚ   Úlitellm._loggingr   Úlitellm._uuidr   Úlitellm.caching.dual_cacher   rj  r   r   r   r   Ú*litellm.litellm_core_utils.duration_parserr    Ú*litellm.litellm_core_utils.safe_json_dumpsr!   Úlitellm.models.credentialsr"   Ú)litellm.proxy._experimental.mcp_server.dbr#   r$   r%   ÚOlitellm.proxy._experimental.mcp_server.outbound_credentials.sso_assertion_storer&   r8  r(   r)   r*   Úlitellm.proxy.auth.auth_checksr+   r,   r-   r.   r/   Úlitellm.proxy.auth.auth_utilsr0   r1   r2   Ú$litellm.proxy.auth.user_api_key_authr3   Ú9litellm.proxy.common_utils.auth_cache_invalidation_pubsubr4   Ú5litellm.proxy.common_utils.callback_config_validationr5   Ú)litellm.proxy.common_utils.callback_utilsr6   r7   Ú-litellm.proxy.common_utils.config_sync_pubsubr8   r9   Ú%litellm.proxy.common_utils.rbac_utilsr:   r[  r<   Ú-litellm.proxy.common_utils.user_api_key_cacher=   Ú.litellm.proxy.hooks.key_management_event_hooksr>   Ú,litellm.proxy.hooks.model_max_budget_limiterr?   Ú/litellm.proxy.management_endpoints.common_utilsr@   rA   rB   rC   rD   rE   rF   rG   Ú=litellm.proxy.management_endpoints.model_management_endpointsrH   Ú6litellm.proxy.management_helpers.access_group_key_syncrI   rJ   rK   Ú3litellm.proxy.management_helpers.key_settings_auditrL   Ú8litellm.proxy.management_helpers.object_permission_utilsrM   rN   rO   rP   rQ   rR   Ú>litellm.proxy.management_helpers.team_member_permission_checksrS   Ú&litellm.proxy.management_helpers.utilsrT   Ú1litellm.proxy.spend_tracking.spend_tracking_utilsrU   Ú7litellm.proxy.ui_crud_endpoints.proxy_setting_endpointsrV   rL  rW   rX   rY   rZ   r[   Ú$litellm.repositories.base_repositoryr\   Ú&litellm.repositories.budget_repositoryr]   Ú&litellm.repositories.config_repositoryr^   r_   Ú+litellm.repositories.credentials_repositoryr`   Ú%litellm.repositories.model_repositoryra   Ú%litellm.repositories.prisma_protocolsrb   Ú'litellm.repositories.table_repositoriesrc   rd   Ú$litellm.repositories.team_repositoryre   Ú$litellm.repositories.user_repositoryrf   Ú2litellm.repositories.verification_token_repositoryrg   Úlitellm.routerrh   Ú+litellm.secret_managers.base_secret_managerri   Úlitellm.secret_managers.mainrj   ÚAlitellm.types.proxy.management_endpoints.key_management_endpointsrk   rl   rm   rn   ro   Úlitellm.types.routerrp   Úlitellm.types.utilsrq   rr   rs   r¨  rt   ru   Úprisma_modelsÚ	BaseModelrv   ry   r•   r™   r¤   r¨   rª   r¬   r®   r°   r’   r¼   ÚGenerateKeyRequestrÁ   r—  ÚMemberrÆ   rÎ   rŒ   Úboolrà   rŽ  ré   r=  r÷   r  rý   r  r  r¤  r  r  r  r  r“   r  r  r$  r%  r—   r2  Ú	frozensetr3  r=  rF  ÚGenerateRequestBaserJ  ÚBudgetLimitEntryrr  r]  rc  ro  rx  rÂ  rÛ  rü  rñ  rû  rþ  r  r	  rú  rû  ræ   Úall_proxy_modelsr
  r  ÚLiteLLM_OrganizationTabler  r  r¿  rÀ  ÚpostrB  rE  rR  ÚRegenerateKeyRequestre  r^  rk  rm  rz  r|  r–  r�  r°  rÆ  rÚ  r!  rÜ  rö  r"  r�  Ú
KeyRequestr  r  r)  r¹   r/  r"  rÁ  rg  rk  r	  r  r‰  r�  rq  r  r¾  rÁ  rÉ  rÌ  rÏ  rÜ  rè  r÷  rù  rÿ  r  r
  r  r  ÚResetSpendRequestr  r  r   r#  r'  r+  r/  r2  r5  r8  r�  rS  rb  r   rw  r|  rŠ  rP  rƒ  r£  ÚBlockKeyRequestr¹  r¾  rÅ  rÊ  r   rà  rÆ  Úcompileré  r»  r¼  r_  r}   r‚   r€   ú<module>r6     s%  ðò	ó Û Û Û Û Û 	Û 	Û Û ß BÓ Bß 2Ñ 2ß X× XÓ Xã Û ß U× UÑ Uã Ý 1Ý Ý 0÷ó õ KÝ AÝ 5÷ñ õ
ô #ß ZÑ Z÷õ ÷ñ õ
 Cõõ `÷÷õ TÝ KÝ IÝ RÝ U÷	÷ 	ó 	õ÷ñ õ
 Y÷÷ õõ OÝ Lõ÷õ õ @Ý Cß PÝ MÝ AÝ >÷õ @Ý ?õõ "Ý SÝ 3÷õ õ ,÷ñ ñ ÝÝ.áÐ/°yÔAÐ ô0�8ô 0ô"2�ô 2ô
!˜(ô 
!ðØÐ0Ñ1ðàÐ#Ñ$óðCØðCàCóCðFØðFàFóFð/˜|ð /°¸\Ñ0Jó /ð lð °|ÀNÑ7Só ð ð Ð2Eó ð
°c¸D±jð 
ÀTó 
ð$Ð)Ð,EÑEó $ðÐ"<ð ÀsÈTÁzð ÐV\Ð_cÑVcó ð5°Cð 5¸Hó 5ð& &*ò	"
Ø
ð"
àð"
ð ˜T‘zð"
ð ˜d™
ð	"
ð
 
ó"
ðJØ%ðà�4‰Zðð �4‰Zðð 
ó	ð4+Ø˜D‘jð+à*ð+ð &ð+ð 3ð	+ð
 ó+ð\Ð/Að ÐTXÐY\ÑT]Ð`dÑTdó ð#Ø*ð#à%ð#ð ð#ð ó	#ðLØ%ðà:¸TÑAóð XØ3°dÑ:ðXà˜DÑ óXð°nð ÐL^ó ð8$^Ø*¨TÑ1ð$^à%ð$^ð ð$^ð ð	$^ð
 
ó$^ðNF°'¸#¸v¸+Ñ2FÈÑ2Mð FÐRVó Fð  ò Ø%ð à
Ð/Ñ
/ð ð ˜‘ð ð ð	 ð
 �4‰Zð ð ˆT�]ó ñF “€ˆÓ ðÐ,ð ¸ð À$ó ñ$ 1:Ð;KÈ]Ð:[Ó0\Ð &¨Ó \ð+
Ø
�dÑ
ð+
à/ð+
ð &ð+
ð 
ó	+
ðd ).Ø$ò(Ø˜4‘Kð(à%ð(ð "&ð	(ð
 ð(ð 
ó(ðVØ
ðà%ðð 
óð,0
ØÐ(Ñ)¨DÑ0ð0
à ™ð0
ð &ð0
ð !ð	0
ð
 +¨TÑ1ð0
ð 
ó0
ðfØ�4‰Zðà $Ñ&óñ> !Ò!qÓrÐ ð
 ò;Ø
Ð/Ñ
/ð;àð;ð 
ó;ð|nØ
ðnà%ðnð ˜d™
ðnð +¨TÑ1ð	nð
 ónðbDØ
Ð,Ñ
-ðDà
Ð/Ñ
/ðDð ˜D‘jðDð ˜D‘jð	Dð
 "& c¨3 h¡ðDð "& c¨3 h¡ðDð ðDð 
óDðN#
Ø
Ð,Ñ
-ð#
à
Ð/Ñ
/ð#
ð ˜D‘jð#
ð ˜D‘jð	#
ð
 ð#
ð 
ó#
ðLØ
Ð,Ñ
-ðà*ðð Ð/Ñ
/ðð 
ó	ð2Ø
Ð,Ñ
-ðà*ðð Ð/Ñ
/ðð 
ó	ð"!Ø*ð!à
Ð/Ñ
/ð!ð  ð!ð 
ó	!ñH %.Ø×&Ò&×,Ò,Ð.?×.PÒ.P×.VÒ.VÐWó%Ð ˜Eó ð
/
Øð/
à
Ð/Ñ
/ð/
ð  ð/
ð (ð	/
ð
 
ó/
ðdØ
Ð,Ñ
-ðà(ðð Ð/Ñ
/ðð 
ó	ðBØ
Ð,Ñ
-ðà(ðð Ð/Ñ
/ðð 
ó	ð2
Ø%ð
àð
ð  ð
ð 
ó	
ð@(Ø(ð(à
Ð/Ñ
/ð(ð  ð(ð 
ó	(ðV ‡‚ØØ
Ð	ÙÐ+Ó,Ð-Ø&ð	 ó ð ñ )0Ð0AÓ(BÙ%+Øð tô&ñM+Ø
ðM+à%ðM+ð ˜d™
òM+ó óðM+ð` ‡‚Ø#Ø
Ð	ÙÐ+Ó,Ð-ð ó ð
 ñ )0Ð0AÓ(BÙ%+Øð tô&ñWØ
ðWà%ðWð ˜d™
òWó óðWðt0 )ð 0Àð 0ÐZ^ð 0Ðcgó 0ðfZØ
Ð1Ñ
1ðZà/ôZðzØðà/ðð 
ôð04Ð,ð 4Ð@Yð 4Ð^bô 4ð
 U¨T¡\ð 
°dô 
ð$ TXòDØ�‰:ðDØ&2°TÑ&9ðDØFIÈDÁjðDàôDðN
"Ð#3ð 
"ÐG`ð 
"Ðehô 
"ð* /3Ø9=ònØ(ðnà%ðnð ˜d™
ðnð   $Ñ&ð	nð
 (ðnð $ðnð ˜‘ðnð % t™Oðnð 0°$Ñ6ðnð 
ˆ#ˆvˆ+Ñônðb%(Ø
ð%(àÐ3Ñ4ð%(ð 0ð%(ð   $Ñ&ð	%(ð
 (ð%(ð ð%(ð ˜DÑ ô%(ðP{bØ
ð{bà/ð{bð &ð{bð ˜‘ð	{bð
 ð{bð ð{bð (ð{bð 
ô{bð| ‡‚ˆ]Ð"2Ð!3Á7ÐK\ÓC]ÐB^€Ó_Øñ )0Ð0AÓ(BÙ%+Øð tô&ñ	_
Øð_
à
ð_
ð &ð_
ð ˜d™
ò	_
ó ó `ñ_
ðD ‡‚ØØ
Ð	ÙÐ+Ó,Ð-Ø(ð	 ó ð ñ )0Ð0AÓ(BÙ%+Øð tô&ñ[Ø
ð[à%ð[ð ˜d™
ò[ó óñ[ð|VØðVáðVð 0°$Ñ6ðVð ô	Vð: ‡‚ØØ
Ð	ÙÐ+Ó,Ð-Ø(ð	 ó ð ñ )0Ð0AÓ(BÙ%+Øð tô&ñnØ
#ðnà%ðnð ˜d™
ònó óñnðbC
Ø	"ðC
á
ðC
ð (ðC
ð ô	C
ðL ‡‚ˆ]Ð"2Ð!3Á7ÐK\ÓC]ÐB^€Ó_Øñ )0Ð0AÓ(BÙ%+Øð tô&ñh+Ù
ðh+à%ðh+ð ˜d™
òh+ó ó `ñh+ðV
Øð
à˜c 7¨3°¨;Ñ#7Ð7Ñ8ð
ð " DÑ(ð
ð 
ˆ#ˆt�C˜�KÑ Ð
 Ñ!ô	
ð ‡‚ØØ
Ð	ÙÐ+Ó,Ð-Øð	 ó ð #Ù(/Ð0AÓ(BñS+Ù
�tÑ
ðS+à%òS+óñS+ðl ‡‚ˆKÐ/Ð0ÁÐHYÓ@ZÐ?[€Ó\Øà#�g—m‘m¨DÐ>]Ô^Ù(/Ð0AÓ(Bño+Ø	ˆt‰ðo+à%òo+ó ó ]ño+ðd d¨3¡i°$Ñ&6ð ÀFÈTÁMð Ðaeð ÐjqÐrvÑjwô ð0  ØØØØØ#'Ø&*Ø"Ø $Ø#ØØ"&ØàØØ!ØØØ!Ø Ø(,ØØ Ø Ø8EØ%)Ø Ø*,Ø!Ø$&Ø$(Ø#'Ø#'Ø!%Ø!%Ø"Ø ØØØ"&Ø!Ø04Ø%)Ø!Ø!Ø"&ØØ"Ø'+Ø=AØ#Ø$(Ø#'Ø)-Ø!%ñstØ˜-Ñ(ðtà�D‰jðtð ðtð ð	tð
 ðtð ðtð ˜D‘Lðtð ˜t™ðtð �t‰|ðtð ˜‘ðtð ˜‘ðtð �D‰[ðtð ˜4‘Zðtð �‰:ðtð 
Ø
ñ
ðtð" �4‰Zð#tð$ �d‘
ð%tð& �4‰Zð'tð( �D‰jð)tð* �d‘
ð+tð, �T‰zð-tð.  ™:ð/tð0 �T‰kð1tð2 �T‰zð3tð4 �T‰zð5tð6 Ð4Ñ5ð7tð8 ˜d‘{ð9tð: �T‰zð;tð< ! 4™Kð=tð> ˜‘ð?tð@ ˜T‘kðAtðB ˜T‘kðCtðD ˜D‘[ðEtðF ˜D‘[ðGtðH ˜$‘;ðItðJ ˜$‘;ðKtðL �t‘ðMtðN �T‰kðOtðP �D‰[ðQtðR �$‰;ðStðT ˜4‘ZðUtðV �d‘
ðWtðX ˜Ñ&¨Ñ-ðYtðZ ˜d‘{ð[tð\ �d‘
ð]tð^ �d‘
ð_tð` ˜4‘Kðatðb �D‰jñctðd �t‘ñetðf  ™*ðgtðh 4°dÑ:ðitðj ˜‘ðktðl ˜T‘zñmtðn ˜D‘[ñotðp ˜3‘i $Ñ&ðqtðr ˜$‘;õstðn	#Ø%ñ#à'ð#ð  ð#ð (õ	#ñLDØ'ðDà'ðDð &ðDð  ð	Dð
 
õDðV &*ó	lØðlà'ðlð &ðlð ˜d™
ð	lñ
 ˆ4�$‰;˜Ð6Ñ7Ð7Ñ8õlðd &*ò5Ø
Ð,Ñ
-ð5à%ð5ð ˜d™
ð5ð 
ˆ$ˆs�Fˆ{Ñ
Ñõ	5ðv óUØ�g˜c 6˜kÑ*Ñ+ðUàñUñ 	ðUð 
õ	Uð. &*ØòØ
Ð,Ñ
-ðàðð &ðð ˜d™
ñ	ñ
 	ðð 
õð2 &*óØ�c‘ðà'ðð  ðð &ð	ð
 ˜d™
ðñ ˆ4�$‰;˜Ð6Ñ7Ð7Ñ8õð(YuØðYuà%ñYuð ñYuð ð	Yuð
 
õYuðx
¨Nð 
¸tõ 
ð ‡‚Ù%Ù
!Ð	"ÙÐ+Ó,Ð-ð ó ñ )0Ð0AÓ(BÙØÙKôñ QØ%ñ Qàó Qóñ
 QðF ‡‚Ù+Ù
!Ð	"ÙÐ+Ó,Ð-ð ó ñ )0Ð0AÓ(Bñ=Ø%ó=óñ
=ð2Ð2°TÑ9ð ¸cõ ð,:
Ù!ñ:
àñ:
ð ñ:
ð ˜‘*ð	:
ð
 
õ:
ðzsàñsð )ñsð ð	sð
 
ðsð  Ñ
%ðsð &ðsð ˜d™
ðsð (ðsð $ðsð õsðl ‡‚Ù Ø
Ð	ÙÐ+Ó,Ð-ð ó ð
 ‡‚ÙØ
Ð	ÙÐ+Ó,Ð-ð ó ð
 àØ(,Ù(/Ð0AÓ(BÙ%+Øð tô&ñ	F+Ø	ˆt‰ðF+à
 Ñ
%ðF+ð &ðF+ð ˜d™
ð	F+ð ˜4ÑóF+ó óóñF+ñRØ(ðà%ðð  ðð (ð	ð
 
õñ:#¨&ñ #Ð=Vð #Ð[`õ #ñLvÀ3ñ vÈuð vÐY]õ vðDx¨°&Ñ)9¸CÑ)?À$Ñ)Fð xÉ5ÐQXÐY\Ð^dÐYdÑQeÑgjÐQjÑKkõ xñ"¨7°3¸°;Ñ+?ð ÀGÈCÐQWÈKÑDXõ ð6&bØñ&bàð&bð ˜FÑ# cÑ)¨DÑ0ð&bð 
õ	&bðR ‡‚Ù!Ø
Ð	ÙÐ+Ó,Ð-ð ó ð
 ñ )0Ð0AÓ(BÙ%+Øð tô&ñ	a+Ø	ða+á
ða+ð &ða+ð ˜d™
ð	a+ð 
ˆ#ˆsˆ(�^óa+ó óña+ðH_Ø%ð_à�4‰Zð_ð �4‰Zð_ð ˜4‘Zð	_ð
 �T‰zñ_ð �D‰jð_ð  ð_ñ ˜Ñõ_ñDSÙ)¨DÑ0ðSàðSð 
Ñ
ÑõSð$Ø%ñàÑ(Ñ)ðð 
ˆ#�YõðØ%ñàÑ(Ñ)ðð 
ˆ#�Yõð(Ø%ñàÑ(Ñ)ðð 
ˆ#�YõñMÙ)¨DÑ0ðMà%ðMð  ðMð 
ˆ#�Yõ	MñNÙ)¨DÑ0ðNà%ðNð  ðNð 
ˆ#�Yõ	Nñ &/±¹)Ð/DÓ%EÑ ˜UÔ Eð ‡‚ÙØ
Ð	ÙÐ+Ó,Ð-ð ó ð
 ñ )0Ð0AÓ(BÙ‘a¡]±qÕ9Ù‘b¡k±a¹CÕ@ÙØñ Xôñ   Ñ2JÔKÙ"'¨Ñ:ZÔ"[Ù  Ñ3LÔMÙ!Øñ Zôñ  % UÑ8PÔQÙ# EÑ7mÔnÙ$)¨%Ñ=_Ô$`ÙØÙOôñ ¡FÑ8VÔWÙ$ TÑ7]Ô^Ù˜tÑ1TÔUÙ" 4Ñ5PÔQÙ"'¨Ñ:ZÔ"[Ù  Ñ3LÔMÙ$Øñ fô ñ  Øñ UôñCu
Øðu
à%ñu
ð ñu
ð ð	u
ð
 �4‰Zðu
ð �4‰Zðu
ð ˜4‘Zñu
ð �D‰jðu
ð �T‰zñu
ð  ñ!u
ð" ñ#u
ð$ "ñ%u
ð& �4‰Zñ'u
ð. ñ/u
ð0 �‰I˜Ññ1u
ð2 �$‰Jð3u
ð4 �d‘
ñ5u
ð6 ˜4‘Zð7u
ð8 �D‰jñ9u
ð: ñ;u
ðB �4‰ZðCu
ñJ óKu
ó óñu
ðp$Ø%ð$àñ$ð �v‘,ñ$ð �c‘ð	$ð
 
õ$ðD ‡‚ÙØ
Ð	ÙÐ+Ó,Ð-ð ó ð
 á(/Ð0AÓ(BÙ‘a™A©=Õ9Ù‘b™Q¡3±KÕ@Ù˜tÑ1fÔgÙ Ñ2aÔbñq
Ø%ñq
à
ñq
ð ñq
ð �$‰Jð	q
ð
 �4‰Zðq
ð 
ˆ#ˆsˆ(�^óq
ó óñq
ñh 3¨¡:ñ ¸3ð À4ÈÈSÈÁ>ÐTXÑCXõ ñ@B°ñ B¸(ð BÀtÈCÐQWÈKÑGXõ Bð )-Ø$)Ø!Ø"&ØØ#(Ø!%òØ�4‰Zðà�4‰Zðð ˜4‘Zðð �T‰zñ	ð
 �D‰jñð ˜4‘Zñð ˜‘I Ñ$ñð ˜#‘Y Ñ%ñð "ðð �d‘
ñð ˜4‘Zðð �D‰jñð !ñð ˜$‘Jðð ˆS�&ˆ[ÑõðV #'Ø$Ø'+àØ$)ØØØ#ØØ!Ø"&ØØ#(Ø!%ò/qØñqà
ñqð ðqð �4‰Zð	qð
 �4‰Zðqð ˜4‘Zðqð �T‰zñqð �D‰jñqð ˜4‘Zñqð ñqð ˜‘I Ñ$ñqð ˜#‘YØ
ññqð "ñqð �4‰Zñqð  ñ!qð" �‰I˜Ññ#qð$ �$‰Jð%qð& �d‘
ñ'qð( ˜4‘Zð)qð* �D‰jñ+qð, !ñ-qð. ˜$‘Jð/qñ0 õ1qðh	¸ÀÀVÀÑ8Lõ 	ð3Ø%ñ3à˜‘*ð3ð   $Ñ&ð3ð (ð	3ð
 ð3ð 
õ3ðl ‡‚‰\Ð!1Ð 2Á'ÐJ[ÓB\ÐA]€Ó^Øñ )0Ð0AÓ(BÙ%+Øð tô&ñ	mÙ
ñmàðmð &ðmð ˜d™
ð	mð  Ñ%ómó ó _ñmð` ‡‚‰^Ð#3Ð"4ÁGÐL]ÓD^ÐC_€Ó`Øñ )0Ð0AÓ(BÙ%+Øð tô&ñ	mÙ
ñmàðmð &ðmð ˜d™
ó	mó ó añmð` ‡‚ÙØ
Ð	ÙÐ+Ó,Ð-Ù$ð	 ó ð ñ )0Ð0AÓ(BñP
ØðP
à%óP
ó óñP
ðfØ%ðà	ˆt‰ñð (ðð 
õ	ð0I
Ø%ðI
àñI
ð ˜' # s (Ñ+Ñ,ðI
ñ õ	I
ðX '˜BŸJšJÑ'[Ó\Ñ �EÔ \ð(
¨#°©*ð (
¸õ (
ð\ &*òØ�T‰zðà $Ñ&ñð ˜d™
ðð 
õ	ðB
°°t±ð 
Àö 
r‚   