Ë
    tPêj/Ü ã                   óT"  — U d Z ddlZddlZddlZddlZddlmZmZ ddlmZ	 ddl
m
Z
mZ ddlmZ ddlmZmZmZmZmZmZmZmZ ddlZddlmZmZmZmZmZmZ dd	lmZm Z  dd
l!m"Z"m#Z# ddl$Z$ddl%m&Z& ddl'm(Z( ddl)m*Z* ddl+m,Z, ddl-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z>m?Z?m@Z@mAZAmBZBmCZCmDZDmEZEmFZFmGZGmHZHmIZImJZJmKZKmLZLmMZMmNZNmOZOmPZPmQZQmRZRmSZSmTZTmUZUmVZV ddlWmXZXmYZYmZZZm[Z[m\Z\m]Z]m^Z^m_Z_m`Z`maZambZb ddlcmdZdmeZe ddlfmgZg ddlhmiZi ddljmkZk ddllmmZm ddlnmoZo ddlpmqZqmrZrmsZsmtZtmuZumvZvmwZwmxZxmyZy ddlzm{Z{ ddl|m}Z} ddl~mZm€Z€m�Z�m‚Z‚mƒZƒ ddl„m…Z…m†Z†m‡Z‡ ddlˆm‰Z‰ ddlŠm‹Z‹mŒZŒ ddl�mŽZŽm�Z�m�Z� ddl‘m’Z’m“Z“m”Z” dd l•m–Z– dd!l—m˜Z˜ 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¦ dd'l§m¨Z¨ dd(l©mªZª dd)l«m¬Z¬m­Z­m®Z®m¯Z¯m°Z°m±Z±m²Z²m³Z³m´Z´mµZµm¶Z¶m·Z· erdd*l¸m¹Z¹ dd+l¸mºZ»  e«       Z¼ee½d,<    ed-«      Z¾ G d.„ d/e#«      Z¿ G d0„ d1e#«      ZÀd2eÁd3eÁfd4„ZÂd5ee¾   d3eÃe¾   fd6„ZÄ G d7„ d8e«      ZÅd9e¤d3d:fd;„ZÆ G d<„ d=e«      ZÇ G d>„ d?e«      ZÈ G d@„ dAeÈeÇe«      ZÉ G dB„ dCe«      ZÊ G dD„ dEe«      ZË G dF„ dGeËe«      ZÌ G dH„ dIe«      ZÍ G dJ„ dKeÈeÇeÊeÌeÍe«      ZÎd9e¢d3dLfdM„ZÏ G dN„ dOe«      ZÐ G dP„ dQe«      ZÑ�dwdR„ZÒ G dS„ dTe#dU¬V«      ZÓ G dW„ dXe#dU¬V«      ZÔ G dY„ dZe#dU¬V«      ZÕ G d[„ d\e#«      ZÖ G d]„ d^e#«      Z× G d_„ d`e€e«      ZØ G da„ dbe«      ZÙ G dc„ dde€e«      ZÚdeZÛee½df<    edgdhi«      ZÜee½di<   dje’dz  d3dkfdl„ZÝ�dxdn„ZÞdje’dz  d3dofdp„Zßdje’dz  d3dqfdr„Zàdje’dz  d3dsfdt„Zádje’dz  d3dufdv„Zâdje’dz  d3dwfdx„Zãdje’dz  d3dyfdz„Zädje’dz  d3d{fd|„Zådje’dz  d3d}fd~„Zædje’dz  d3dfd€„Zçd2eÁd3eèfd�„Zéd‚eÉdƒemd„e“d3dfd…„Zêd†e;d‡eVd3dfdˆ„Zë G d‰„ dŠ«      Zìd‹eèd3eÁfdŒ„Zíd�eèd‡eVd3eîfdŽ„Zï	 �dydje’d�eÃeè   d�eèdz  d3eÃe:   fd‘„Zðd’eÃe;   d“eAeUz  d”eñdz  d•eñdz  d–eòeèeñf   d—eòeèeñf   d˜eèd3dfd™„Zód’eÃe;   d“eAeUz  d”eñdz  d•eñdz  d˜eèd3dfdš„Zôd’eÃe;   d›e8d“eAeUz  d3dfdœ„Zõd’eÃe;   d›e8d“eAeUz  d3dfd�„Zöd›e8d“eAeUz  dje’d3dfdž„Z÷d“eAeUz  d‡eVdje’dƒemd3df
dŸ„Zød“eUd‡eVd eùdz  d3dfd¡„Zúd‡eVd¢eeèeÁf   d3eîfd£„Zûe¼�jù                  d¤d¥g eeg«      ge;¬¦«      e� eeg«       edd§¬¨«      fd“eAd©ed‡eVdªeèdz  fd«„«       «       Zýd¬eÍd­eòd�eèdªeèdz  d‡eVd®eèd3dfd¯„Zþd“eUd°eñdz  dje’d‡eVd®eèd3eñdz  fd±„Zÿd²e;d³e9dje’d3dfd´„�Z 	 �dydµeèd¬eÇd¶e¨dz  dje’d‡eVdz  d3d·fd¸„�Z	 �dzd²e;d³e9d¶e¨d¹eîd3eîf
dº„�Ze¼�jù                  d»d¥g eeg«      g¬¼«      e� eeg«       edd§¬¨«      fd“eUd©ed‡eVdªeèdz  fd½„«       «       �Ze¼�j	                  d¾d¥g eeg«      ge;¬¦«      	 �dyd�eèd“eCd©ed‡eeV eeg«      f   dªeeèdz   ed§¬¨«      f   f
d¿„«       �Zd“eUd­eòd3dfdÀ„�ZdÁeòd¬eÊd3eòfdÂ„�ZdÃe@eÃe@   z  dÄeîfdÅ„�Zdje’dz  d“eOdÄeîfdÆ„�Z	d“eOd¬e;fdÇ„�Z
d‡eVdÈe;d“eOd3dfdÉ„�Z	 �dyd“eOdÈe;dje’d‡eVd®eèdmeŽdz  d3�eeÃe=   eÃe:   f   fdÊ„�ZdÃe@dËee=   d3e@fdÌ„�ZdÃe@dÈe;d3eîfdÍ„�Zd“eOdÈe;dËeÃe=   d3dfdÎ„�Zd“eOdÈe;dje’d‡eVd®eèd3�edÏeÃe=   eÃe:   f   fdÐ„�Zd²e;d3dfdÑ„�ZdÒee@   dje’d3�eeè   fdÓ„�ZdÒee@   dÔ�eeè   dÕ�eeè   d3�eeè   fdÖ„�Zd×�Zee½dØ<   dÒee@   dÕ�eeè   d‡eVd3dfdÙ„�ZdÒee@   d3eèfdÚ„�Zd�eèdËee=   dÕ�eeè   dÛee@   dÜee@   d‡eVd®eèd3dfdÝ„�ZdÃe@dje’d3e@fdÞ„�Ze¼�jù                  dßd¥g eeg«      geK¬¦«      e� eeg«      fd“eOd‡eVfdà„«       «       �ZdÃe@d“ePd3eîfdá„�Zd¬e;d“ePd3�e�ee@dâf   eÃe@   f   fdã„�Ze¼�jù                  däd¥g eeg«      g¬¼«      e� eeg«      fd“ePd‡eVfdå„«       «       �Zdædçdèdédêdëœ�Zee½dì<   d“eQd3eòeèeÁf   fdí„�Z e¼�jù                  dîd¥g eeg«      geR¬¦«      e� eeg«      fd“eQd©ed‡eVfdï„«       «       �Z!d�eèd‡eVd3dfdð„�Z"dñeñdòeèd3efdó„�Z#dôeÁdõe:d3eùfdö„�Z$e¼�jù                  d÷d¥g eeg«      f¬¼«      e�d�eèd�eèd“eFd‡eeV eeg«      f   fdø„«       «       �Z%dÒeÃe@   dùeKd3eÃe´   fdú„�Z&e¼�jù                  dûd¥g eeg«      ge­¬¦«      e� eeg«      fd“e¬d‡eVfdü„«       «       �Z'e¼�jù                  dýd¥g eeg«      g¬¼«      e� eeg«       edd§¬¨«      fd“e2d©ed‡eVdªeèdz  fdþ„«       «       �Z(d�eeè   dje’d3dfdÿ„�Z)d�eeè   dmeÚd3df�d „�Z*�d�ddƒemd„e“d3df�d„�Z+d’ee;   dƒemd„e“d3df�d„�Z,	 �dyd’eÃe;   d‡eVdªeèdz  d3eÃeòeèeÁf      f�d„�Z-�deÃeòeèeÁf      dje’d3df�d„�Z.	 �dyd’eÃe;   dje’d‡eVdªeèdz  d3df
�d„�Z/d‡eV�d	e;f�d
„�Z0�deèdje’�deMd3eMf�d„�Z1dje’dÒee@   d3�ee@dâf   f�d„�Z2�deMd3eMf�d„�Z3e¼�ji                  �dd¥g eeg«      g¬¼«      e� e�jj                  d�d�¬«       e�jj                  d�dd�¬«       eeg«      fd©ed�eè�deñdz  d‡eVf�d„«       «       �Z6e¼�ji                  �dd¥g eeg«      geµ¬¦«      e� eeg«      fd©ed�eèd‡eVf�d„«       «       �Z7e¼�jù                  �dd¥g eeg«      g¬¼«      e� eeg«      fd“e/d©ed‡eVf�d„«       «       �Z8e¼�jù                  �dd¥g eeg«      g¬¼«      e� eeg«      fd“e/d©ed‡eVf�d„«       «       �Z9e¼�ji                  �dd¥g eeg«      fe¶¬¦«      �d„ «       �Z:e¼�ji                  �d «       eeg«      eÃe;   fd©ed‡eVf�d!„«       �Z;d�eèdje’dƒemd„e“d3eÃeè   dz  f
�d"„�Z<	 	 	 	 	 �d{dje’d�eèdz  �d$eèdz  dµeèdz  d�eèdz  �d%eî�d&eèdz  �d'e±�d(eÃeè   dz  dƒemdz  d„e“dz  d3eòeèeÁf   dz  f�d)„�Z=�d*eÃeè   d3�d+f�d,„�Z>	 �dyd’e�d%eî�d-eòeèeñf   dz  d3eÃe²e;z  e4z     f�d.„�Z?dje’d’eeÈ   d3eòeèeñf   f�d/„�Z@d‡eVd�eèdz  dµeèdz  dje’dƒemd„e“d3�eeèdz  eÃeè   dz  f   f�d0„�ZAe¼�ji                  �d1d¥ge³ eeg«      g�¬2«      e� e�jj                  d�d3�¬«       e�jj                  d�d4�¬«       e�jj                  d�d5�¬«       e�jj                  d�d6�¬«       e�jj                  d�d7�¬«      �d# e�jj                  �d8�d9�d8�¬:«       e�jj                  d×�d;�d8�d<�¬=«       e�jj                  d�d>�¬«       e�jj                  �d?�d@�¬«       e�jj                  d�dA�¬«       eeg«      fd©ed�eèdz  dµeèdz  d�eèdz  �d$eèdz  �d&eèdz  �d'ee± e�jj                  �dB¬¨«      f   �dCeñ�dDeñ�dEeèdz  �dFeè�dGeèdz  d‡eVf�dH„«       «       �ZBd‡eVd�eèdz  dje’dƒemd„e“d3eÃf�dI„�ZCe¼�ji                  �dJd¥g eeg«      g¬¼«      e� e�jj                  d�d3�¬«      d eeg«      fd©ed�eèdz  dµeèdz  d‡eVf�dK„«       «       �ZD	 	 �d|dje’�dDeñ�dCeñd3�eeÃe;   eñf   f�dL„�ZEe¼�ji                  �dMd¥g eeg«      gdU�dN�dOeÃe;   ii�¬P«       e�jj                  d�d�¬«       e�jj                  d�dQ�¬«       e�jj                  �d8�d9�d8�¬:«       e�jj                  �dR�dS�d8�d<�¬=«       eeg«      fd�eèdz  �d$eèdz  �dCeñ�dDeñd‡eVf
�dT„«       �ZFd†e;�dUeÃeè   d3eÃeè   f�dV„�ZGe¼�jù                  �dWd¥g eeg«      g¬¼«      e� eeg«      fd“eSd©ed‡eVf�dX„«       «       �ZHe¼�jù                  �dYd¥g eeg«      g¬¼«      e� eeg«      fd“eTd©ed‡eVf�dZ„«       «       �ZIe¼�ji                  �d[d¥g eeg«      g¬¼«      e� e�jj                  d�d�¬«       eeg«      fd�eèd‡eVd3e°f�d\„«       «       �ZJe¼�jù                  �d]d¥g eeg«      g¬¼«       eeg«      fd“e·d©ed‡eVd3e;f�d^„«       �ZKe¼�jù                  �d_d¥g eeg«      ge¯¬¦«      e� eeg«      fd“e®d‡eVf�d`„«       «       �ZLd’�da�db�eMd3eñf�dc„�ZNdje’d�eÃeè   �db�eMd3eñf�dd„�ZOdje’�db�eMd3eñf�de„�ZPdñeñdòeèd3ef�df„�ZQ G �dg„ �dhe«      �ZRd�eèdz  �dieèdz  �djeèdz  d‡eVdje’dƒemd„e“d3�eRf�dk„�ZSe¼�ji                  �dleªd¥g�¬m«      	 	 	 	 	 	 	 	 �d}d‡eeV eeg«      f   d�eèdz  �dneèdz  �doeèdz  �dOeèdz  �djeèdz  �dCeñ�dDeñ�dieèdz  f�dp„«       �ZT�dq�ZUee½�dr<   �dneèdz  �doeèdz  d3eèdz  f�ds„�ZVe¼�ji                  �dteªd¥g�¬m«      	 	 	 	 	 	 	 �d~d‡eeV eeg«      f   d�eèdz  �dneèdz  �doeèdz  �dOeèdz  �djeèdz  �dieèdz  �dueñdz  f�dv„«       �ZWy(  za
TEAM MANAGEMENT

All /team management endpoints

/team/new
/team/info
/team/update
/team/delete
é    N)ÚMappingÚSequence)ÚSet)ÚdatetimeÚtimezone)ÚMappingProxyType)ÚTYPE_CHECKINGÚ	AnnotatedÚFinalÚ
NamedTupleÚNoReturnÚProtocolÚTypeVarÚcast)Ú	APIRouterÚDependsÚHeaderÚHTTPExceptionÚRequestÚstatus)Ú	BaseModelÚ	JsonValue)ÚReadOnlyÚ	TypedDict)Úverbose_proxy_logger)Úuuid)ÚPrometheusLogger)Ú
safe_dumps))Ú
UI_TEAM_IDÚBlockTeamRequestÚBudgetNewRequestÚCommonProxyErrorsÚDeleteTeamRequestÚLiteLLM_AuditLogsÚLiteLLM_DeletedTeamTableÚ)LiteLLM_ManagementEndpoint_MetadataFieldsÚ1LiteLLM_ManagementEndpoint_MetadataFields_PremiumÚLiteLLM_ModelTableÚLiteLLM_OrganizationTableÚ$LiteLLM_OrganizationTableWithMembersÚLiteLLM_TeamMembershipÚLiteLLM_TeamTableÚLiteLLM_TeamTableCachedObjÚLiteLLM_UserTableÚLitellmTableNamesÚLitellmUserRolesÚMemberÚNewTeamRequestÚ	OrgMemberÚPatchTeamRequestÚProxyErrorTypesÚProxyExceptionÚResetSpendRequestÚSpecialManagementEndpointEnumsÚSpecialModelNamesÚSpecialProxyStringsÚTeamAccessGroupModelGrantÚTeamAddMemberResponseÚTeamInfoResponseObjectÚTeamInfoResponseObjectTeamTableÚTeamListResponseObjectÚTeamMemberAddRequestÚTeamMemberDeleteRequestÚTeamMemberUpdateRequestÚTeamMemberUpdateResponseÚTeamModelAddRequestÚTeamModelDeleteRequestÚUpdateTeamRequestÚUserAPIKeyAuth)ÚOrganizationNotFoundErrorÚ_cache_team_objectÚ allowed_route_check_inside_routeÚcan_org_access_modelÚdelete_cache_key_objectsÚdelete_cache_team_objectÚget_org_objectÚget_team_membershipÚget_team_objectÚget_user_objectÚ"invalidate_team_member_spend_state)Ú0enforce_batch_enqueued_token_limit_is_admin_onlyÚ-enforce_output_token_estimates_are_admin_only)Úuser_api_key_auth)Úencrypt_callback_vars)Úapply_json_merge_patch)ÚUserApiKeyCache)Úget_daily_activity_aggregated)	Ú+_check_passthrough_routes_caller_permissionÚ_is_user_org_admin_for_teamÚ_is_user_team_adminÚ_set_object_metadata_fieldÚ_team_member_has_permissionÚ_update_metadata_fieldsÚ_upsert_budget_and_membershipÚ_user_has_admin_viewÚvalidate_budget_duration)Úadd_member_to_organization)Úget_daily_activity)ÚTEAM_ADVISORY_LOCK_SQLÚAccessGroupSyncTxÚinvalidate_access_group_cachesÚ&reconcile_team_access_group_membershipÚ!sync_team_access_group_membership)Ú_set_object_permissionÚ1enforce_all_proxy_mcp_servers_grant_is_admin_onlyÚ&handle_update_object_permission_common)ÚTeamMemberPermissionChecks)ÚTEAM_METADATA_SCHEMA_REGISTRYÚ$validate_team_metadata_if_configured)ÚMemberWriteTxÚadd_new_memberÚmanagement_endpoint_wrapper)ÚPrismaClientÚProxyLoggingÚhandle_exception_on_proxy)ÚBudgetRepository)ÚOrganizationRepository)ÚTableActions)ÚAccessGroupRepositoryÚDeletedTeamRepositoryÚModelTableRepositoryÚ OrganizationMembershipRepositoryÚTeamMembershipRepository)ÚTeamRepository)ÚUserRepository)ÚVerificationTokenRepository)ÚRouter)ÚSpendAnalyticsPaginatedResponse)ÚBulkTeamMemberAddRequestÚBulkTeamMemberAddResponseÚ&BulkUpdateTeamMemberPermissionsRequestÚ'BulkUpdateTeamMemberPermissionsResponseÚ GetTeamMemberPermissionsResponseÚTeamIdSearchMatchÚTeamListItemÚTeamListResponseÚTeamMemberAddResultÚTeamMemberInfoResponseÚTeamMetadataSchemaResponseÚ"UpdateTeamMemberPermissionsRequest)ÚPrisma)ÚmodelsÚrouterÚ
_DbRecordTc                   ó   — e Zd ZU eed<   y)Ú_TeamIdKeyCountÚteam_idN)Ú__name__Ú
__module__Ú__qualname__ÚintÚ__annotations__© ó    úv/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/management_endpoints/team_endpoints.pyr”   r”   ¸   s   … Ø„Lrœ   r”   c                   ó"   — e Zd ZU eed<   eed<   y)Ú_TeamIdGroupRowr•   Ú_countN)r–   r—   r˜   Ústrrš   r”   r›   rœ   r�   rŸ   rŸ   ¼   s   … ØƒLØÔrœ   rŸ   ÚvalueÚreturnc                 ó   — | S ©Nr›   )r¢   s    r�   Ú
_as_objectr¦   Á   s   € Ø€Lrœ   Úrowsc                 ó   — t        d| «      S )Nzlist[_DbRecordT])r   )r§   s    r�   Ú_as_listr©   Å   s   € ÜØ˜Dóð rœ   c                   ó(   — e Zd Zededz  fd„«       Zy)Ú
_UserIdRowr£   Nc                  ó   — y r¥   r›   ©Úselfs    r�   Úuser_idz_UserIdRow.user_idÌ   s   € Ø%(rœ   )r–   r—   r˜   Úpropertyr¡   r¯   r›   rœ   r�   r«   r«   Ë   s   „ ØØ(˜˜t™Ò(ó Ù(rœ   r«   ÚrepozTableActions[_UserIdRow]c                 ó   — | j                   S r¥   )Útable©r±   s    r�   Ú_user_id_rows_dbrµ   Ð   s   € Ø�:‰:Ðrœ   c                   ó"   — e Zd Zdeeef   fd„Zy)Ú_ModelDumpRowr£   c                  ó   — y r¥   r›   r­   s    r�   Ú
model_dumpz_ModelDumpRow.model_dumpÕ   ó   � rœ   N)r–   r—   r˜   r   r¡   Úobjectr¹   r›   rœ   r�   r·   r·   Ô   s   „ Ø5˜G C¨ KÑ0Ô5rœ   r·   c                   ó"   — e Zd Zedefd„«       Zy)Ú
_TeamIdRowr£   c                  ó   — y r¥   r›   r­   s    r�   r•   z_TeamIdRow.team_idÙ   s   € Ø!rœ   N)r–   r—   r˜   r°   r¡   r•   r›   rœ   r�   r½   r½   Ø   s   „ ØØ!˜Ò!ó Ù!rœ   r½   c                   ó   — e Zd Zy)Ú_CacheableTeamRowN)r–   r—   r˜   r›   rœ   r�   rÀ   rÀ   Ý   s   … rœ   rÀ   c                   ó(   — e Zd Zededz  fd„«       Zy)Ú_ObjectPermissionRowr£   Nc                  ó   — y r¥   r›   r­   s    r�   Úobject_permission_idz)_ObjectPermissionRow.object_permission_idá   s   € Ø25rœ   )r–   r—   r˜   r°   r¡   rÄ   r›   rœ   r�   rÂ   rÂ   à   s   „ ØØ5 c¨D¡jÒ5ó Ù5rœ   rÂ   c                   óD   — e Zd Zededz  fd„«       Zededz  fd„«       Zy)Ú_TeamAliasBudgetRowr£   Nc                  ó   — y r¥   r›   r­   s    r�   Ú
team_aliasz_TeamAliasBudgetRow.team_aliasæ   s   € Ø(+rœ   c                  ó   — y r¥   r›   r­   s    r�   Úbudget_durationz#_TeamAliasBudgetRow.budget_durationé   ó   € Ø-0rœ   )r–   r—   r˜   r°   r¡   rÈ   rÊ   r›   rœ   r�   rÆ   rÆ   å   s0   „ ØØ+˜C $™JÒ+ó Ø+àØ0  t¡Ò0ó Ù0rœ   rÆ   c                   ó(   — e Zd ZU eeef   dz  ed<   y)Ú_TeamBudgetRowNÚmetadata)r–   r—   r˜   r   r¡   r   rš   r›   rœ   r�   rÍ   rÍ   í   s   … Ø�c˜9�nÑ%¨Ñ,Ô,rœ   rÍ   c                   ó"   — e Zd Zddœdedefd„Zy)Ú_AuditableTeamRowF©Úexclude_nonerÒ   r£   c                 ó   — y r¥   r›   )r®   rÒ   s     r�   Újsonz_AuditableTeamRow.jsonò   rº   rœ   N)r–   r—   r˜   Úboolr¡   rÔ   r›   rœ   r�   rÐ   rÐ   ñ   s   „ Ø+0Ò= DÐ=°SÔ=rœ   rÐ   c                   ó¨   — e Zd Zedeeeef      dz  f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ededz  fd„«       Zy)Ú_RawTeamRowr£   Nc                  ó   — y r¥   r›   r­   s    r�   Úmembers_with_rolesz_RawTeamRow.members_with_rolesö   s   € ð .1rœ   c                  ó   — y r¥   r›   r­   s    r�   Úorganization_idz_RawTeamRow.organization_idû   rË   rœ   c                  ó   — y r¥   r›   r­   s    r�   Ú
max_budgetz_RawTeamRow.max_budgetþ   s   € Ø*-rœ   c                  ó   — y r¥   r›   r­   s    r�   Úsoft_budgetz_RawTeamRow.soft_budget  s   € Ø+.rœ   c                  ó   — y r¥   r›   r­   s    r�   Úmodel_idz_RawTeamRow.model_id  s   € Ø&)rœ   )r–   r—   r˜   r°   r   Údictr¡   r»   rÙ   rÛ   ÚfloatrÝ   rß   r™   rá   r›   rœ   r�   r×   r×   õ   s�   „ Øð1à	�$�s˜F�{Ñ#Ñ	$ tÑ	+ò1ó ð1ð Ø0  t¡Ò0ó Ø0àØ-˜E D™LÒ-ó Ø-àØ.˜U T™\Ò.ó Ø.àØ)˜# ™*Ò)ó Ù)rœ   r×   úTableActions[_RawTeamRow]c                 ó.   — t        d| j                  «      S )Nrä   )r   r³   r´   s    r�   Ú_raw_team_dbræ     s   € ÜØ# T§Z¡Zóð rœ   c                   ó"   — e Zd Zedefd„«       Zy)Ú_BudgetIdRowr£   c                  ó   — y r¥   r›   r­   s    r�   Ú	budget_idz_BudgetIdRow.budget_id  s   € Ø #rœ   N)r–   r—   r˜   r°   r¡   rê   r›   rœ   r�   rè   rè     s   „ ØØ#˜3Ò#ó Ù#rœ   rè   c                   ó    — e Zd Zdededefd„Zy)Ú_BudgetWriteCallÚ
budget_objÚuser_api_key_dictr£   c              ƒ   ó   K  — y ­wr¥   r›   )r®   rí   rî   s      r�   Ú__call__z_BudgetWriteCall.__call__  ó   è ø� ùó   ‚N)r–   r—   r˜   r!   rG   rè   rð   r›   rœ   r�   rì   rì     s   „ ØrÐ)9ÐrÈnÐrÐamÔrrœ   rì   c                 ó   — | S r¥   r›   )Úfns    r�   Ú_as_budget_writerõ     s   € Ø€Irœ   c                   óJ   — e Zd ZU eed<   eed<   eeef   ed<   eeef   ed<   y)Ú_TeamFindManyArgsÚtakeÚskipÚorderÚcursorN)r–   r—   r˜   r™   rš   r   r¡   r»   r›   rœ   r�   r÷   r÷     s*   … Ø
ƒIØ
ƒIØ�3˜�8ÑÓØ�C˜�KÑ Ô rœ   r÷   F)Útotalc                   ó6   — e Zd ZU eeef   ed<   eeef   ed<   y)Ú_TeamUiViewFiltersr•   rÈ   N)r–   r—   r˜   r   r¡   rš   r›   rœ   r�   rþ   rþ   "  s    … Ø�S˜#�XÑÓØ˜˜S˜Ñ!Ô!rœ   rþ   c                   ó(   — e Zd ZU eeee   f   ed<   y)Ú_TeamIdInFilterr•   N)r–   r—   r˜   r   r¡   r   rš   r›   rœ   r�   r   r   '  s   … Ø�S˜( 3™-Ð'Ñ(Ô(rœ   r   c                   ó$   — e Zd ZU eee      ed<   y)Ú_DeletedTeamsResultÚdeleted_teamsN)r–   r—   r˜   r   r   r¡   rš   r›   rœ   r�   r  r  +  s   … Ø˜H S™MÑ*Ô*rœ   r  c                   ó   — e Zd ZU ee   ed<   y)Ú_ErrorDetailÚerrorN)r–   r—   r˜   r   r¡   rš   r›   rœ   r�   r  r  /  s   … Ø�C‰=Ôrœ   r  c                   ó   — e Zd Zedd„«       Zy)Ú_TeamCreateTxc                  ó   — y r¥   r›   r­   s    r�   Úlitellm_teamtablez_TeamCreateTx.litellm_teamtable4  ó   € ØTWrœ   N©r£   ú-TableActions[prisma_models.LiteLLM_TeamTable])r–   r—   r˜   r°   r
  r›   rœ   r�   r  r  3  s   „ ØÚWó ÙWrœ   r  c                   ó4   — e Zd ZdZedd„«       Zedd„«       Zy)Ú_MemberDeleteTxaˆ  The tables `/team/member_delete` reads while it holds the team's advisory lock.

    Reading them off the transaction keeps the whole endpoint on the one pooled connection
    it already checked out: a request that has the lock but still needs another connection
    can be starved by the lock waiters, which is a deadlock rather than a wait when enough
    of them hold the rest of the pool.c                  ó   — y r¥   r›   r­   s    r�   Úlitellm_usertablez!_MemberDeleteTx.litellm_usertable@  r  rœ   c                  ó   — y r¥   r›   r­   s    r�   Úlitellm_verificationtokenz)_MemberDeleteTx.litellm_verificationtokenC  s   € Ødgrœ   N)r£   ú-TableActions[prisma_models.LiteLLM_UserTable])r£   ú5TableActions[prisma_models.LiteLLM_VerificationToken])r–   r—   r˜   Ú__doc__r°   r  r  r›   rœ   r�   r  r  8  s%   „ ñ*ð ÚWó ØWàÚgó Ùgrœ   r  c                   óD   — e Zd Zdededefd„Zedd„«       Zed	d„«       Z	y)
Ú_TeamDeleteTxÚqueryÚargsr£   c              ‡   ó   K  — y ­wr¥   r›   )r®   r  r  s      r�   Úexecute_rawz_TeamDeleteTx.execute_rawH  rñ   rò   c                  ó   — y r¥   r›   r­   s    r�   r
  z_TeamDeleteTx.litellm_teamtableJ  r  rœ   c                  ó   — y r¥   r›   r­   s    r�   Úlitellm_teammembershipz$_TeamDeleteTx.litellm_teammembershipM  s   € Ø^arœ   Nr  )r£   ú2TableActions[prisma_models.LiteLLM_TeamMembership])
r–   r—   r˜   r¡   r»   r™   r  r°   r
  r  r›   rœ   r�   r  r  G  s0   „ ØF sÐF°6ÐF¸cÓFàÚWó ØWàÚaó Ùarœ   r  zV
UPDATE "LiteLLM_UserTable" SET teams = array_remove(teams, $1) WHERE $1 = ANY(teams)
Ú"_STRIP_DELETED_TEAM_FROM_USERS_SQLÚlitellm_model_tableTÚ_INCLUDE_MODEL_TABLEÚprisma_clientr  c                 ó,   — t        | «      j                  S r¥   )r~   r³   ©r$  s    r�   Ú_team_dbr'  X  ó   € Ü˜-Ó(×.Ñ.Ð.rœ   Útxc                 ó.   — t        d| j                  «      S )Nr  )r   r
  )r)  s    r�   Ú_team_tx_dbr+  \  s   € ÜØ7¸×9MÑ9Móð rœ   r   c                 ó,   — t        | «      j                  S r¥   )r}   r³   r&  s    r�   Ú_team_membership_dbr-  b  s   € Ü# MÓ2×8Ñ8Ð8rœ   r  c                 ó,   — t        | «      j                  S r¥   )r   r³   r&  s    r�   Ú_user_dbr/  f  r(  rœ   z.TableActions[prisma_models.LiteLLM_ModelTable]c                 ó,   — t        | «      j                  S r¥   )r{   r³   r&  s    r�   Ú	_model_dbr1  j  s   € Ü Ó.×4Ñ4Ð4rœ   z5TableActions[prisma_models.LiteLLM_OrganizationTable]c                 ó,   — t        | «      j                  S r¥   )rw   r³   r&  s    r�   Ú_org_dbr3  n  s   € Ü! -Ó0×6Ñ6Ð6rœ   z:TableActions[prisma_models.LiteLLM_OrganizationMembership]c                 ó,   — t        | «      j                  S r¥   )r|   r³   r&  s    r�   Ú_org_membership_dbr5  r  s   € ô ,¨MÓ:×@Ñ@Ð@rœ   z/TableActions[prisma_models.LiteLLM_BudgetTable]c                 ó,   — t        | «      j                  S r¥   )rv   r³   r&  s    r�   Ú
_budget_dbr7  x  s   € Ü˜MÓ*×0Ñ0Ð0rœ   z4TableActions[prisma_models.LiteLLM_DeletedTeamTable]c                 ó,   — t        | «      j                  S r¥   )rz   r³   r&  s    r�   Ú_deleted_team_dbr9  |  ó   € Ü  Ó/×5Ñ5Ð5rœ   z4TableActions[prisma_models.LiteLLM_AccessGroupTable]c                 ó,   — t        | «      j                  S r¥   )ry   r³   r&  s    r�   Ú_access_group_dbr<  €  r:  rœ   r  c                 ó,   — t        | «      j                  S r¥   )r€   r³   r&  s    r�   Ú
_tokens_dbr>  „  s   € Ü& }Ó5×;Ñ;Ð;rœ   c                 ó’   — 	 t        | «      }|j                  dd«      j                  dd«      S # t        $ r t        | «      }Y Œ8w xY w)zAStrip CR/LF from user-controlled values to prevent log injection.úÚ ú
)r¡   Ú	ExceptionÚreprÚreplace)r¢   Útexts     r�   Ú_sanitize_for_logrG  ˆ  sJ   € ðÜ�5‹zˆð �<‰<˜˜bÓ!×)Ñ)¨$°Ó3Ð3øô ò Ü�E‹{Šðús   ‚/ ¯AÁAÚteam_rowÚuser_api_key_cacheÚproxy_logging_objc              ƒ   ó”   K  — t        | j                  t        j                  | j	                  «       «      ||¬«      ƒ d{  –—†  y7 Œ­w)a…  
    Refresh the in-memory cached team object after a DB write.

    Every endpoint that mutates `litellm_teamtable` must call this so the
    cached `LiteLLM_TeamTableCachedObj` used by `common_checks` stays in
    sync. Without this, subsequent auth checks read a stale team and can
    403 on permissions the DB has already granted (or, symmetrically,
    keep granting permissions the DB has already revoked).

    `team_row` is the Prisma row returned by `update`/`find_unique` on
    `litellm_teamtable`. It is converted to `LiteLLM_TeamTableCachedObj`
    via `model_dump()` to match the cache shape `_cache_team_object`
    expects.
    )r•   Ú
team_tablerI  rJ  N)rI   r•   r-   Úmodel_validater¹   ©rH  rI  rJ  s      r�   Ú_refresh_cached_teamrO  ‘  s@   è ø€ ô& Ø× Ñ Ü-×<Ñ<¸X×=PÑ=PÓ=RÓSØ-Ø+ô	÷ ò ús   ‚>AÁ AÁAÚteam_objrî   c              ƒ   óÈ   K  — |j                   t        j                  k(  ryt        || ¬«      ryt	        || ¬«      ƒ d{  –—† ryt        t        j                  d¬«      ‚7 Œ ­w)a  
    Verify the caller is authorized to manage the given team.

    Access is granted if:
    - Caller is a proxy admin, OR
    - Caller is an org admin for the team's organization, OR
    - Caller is a team admin of this team

    Raises HTTPException(403) otherwise.
    N©rî   rP  z#You do not have access to this team©Ústatus_codeÚdetail)Ú	user_roler0   ÚPROXY_ADMINr\   r[   r   r   ÚHTTP_403_FORBIDDEN©rP  rî   s     r�   Ú_verify_team_accessrZ  ¬  sb   è ø€ ð ×"Ñ"Ô&6×&BÑ&BÒBØäÐ->ÈÕRØä(Ð;LÐW_Ô`×`Ð`Øä
Ü×-Ñ-Ø4ôð ð aús   ‚=A"¿A Á !A"c                   óÒ  — e Zd ZdZdZededz  ddfd„«       Ze	 	 	 	 ddedz  de	dz  d	e	dz  d
e
dz  def
d„«       Zedddd e«       fdeez  dedededz  de	dz  d	e	dz  d
e
dz  dee
   defd„«       Zedddd e«       fdededededz  de	dz  d	e	dz  d
e
dz  dee
   defd„«       Zededdfd„«       Zededddededef
d„«       Zede
deeee
ef   z     de
deddf
d„«       Zy)ÚTeamMemberBudgetHandlerzHHelper class to handle team member budget, RPM, and TPM limit operations)Úteam_member_budget_idrÎ   Nr£   c                 ót   — t        | t        «      syt        j                  D ]  }| j	                  |d«       Œ y)z>Remove server-owned metadata keys from a caller-supplied dict.N)Ú
isinstancerâ   r\  ÚSYSTEM_MANAGED_METADATA_KEYSÚpop)rÎ   Úkeys     r�   Ú"strip_system_managed_metadata_keysz:TeamMemberBudgetHandler.strip_system_managed_metadata_keysÐ  s4   € ô ˜(¤DÔ)ØÜ*×GÑGò 	$ˆCØ�L‰L˜˜dÕ#ñ	$rœ   Úteam_member_budgetÚteam_member_rpm_limitÚteam_member_tpm_limitÚteam_member_budget_durationc                 ó0   — t        | du|du|du|dug«      S )z,Check if any team member limits are providedN)Úany©rd  re  rf  rg  s       r�   Úshould_create_budgetz,TeamMemberBudgetHandler.should_create_budgetØ  s6   € ô à"¨$Ð.Ø%¨TÐ1Ø%¨TÐ1Ø+°4Ð7ð	ó
ð 	
rœ   ÚdataÚnew_team_data_jsonrî   Úexplicitly_set_fieldsc              ƒ   ó6  K  — ddl m} ddlm}	 | j                  �?d| j                  j                  dd«      › dt        j                  «       j                  › �}
n!d	t        j                  «       j                  › �}
 ||
d
|v r|n| j                  xs |¬«      }|�||_
        |�||_        |�||_        |�||_	         t        |	«      ||¬«      ƒ d{  –—† }|j                  d«      €i |d<   |j                  |d   d<   t         j#                  |«       |S 7 ŒC­w)zÕCreate team member budget table with provided limits.

        The team's own reset period is only inherited when the caller left the
        member duration out, so an explicit null means "never resets".
        r   ©r!   )Ú
new_budgetNzteam-ú ú-z-budget-zteam-budget-rg  )rê   rÊ   ©rí   rî   rÎ   r]  )Úlitellm.proxy._typesr!   Ú>litellm.proxy.management_endpoints.budget_management_endpointsrq  rÈ   rE  r   Úuuid4ÚhexrÊ   rÝ   Ú	rpm_limitÚ	tpm_limitrõ   Úgetrê   r\  Ú_clean_team_member_fields)rl  rm  rî   rd  re  rf  rg  rn  r!   rq  rê   Úbudget_requestÚteam_member_budget_tables                r�   Úcreate_team_member_budget_tablez7TeamMemberBudgetHandler.create_team_member_budget_tableé  s=  è ø€ õ  	:õ	
ð �?‰?Ð&Ø §¡× 7Ñ 7¸¸SÓ AÐBÀ(Ì4Ï:É:Ë<×K[ÑK[ÐJ\Ð]‰Ià&¤t§z¡z£|×'7Ñ'7Ð&8Ð9ˆIñ !1Øð 1Ð4IÑIñ ,à×)Ñ)ÒHÐ-Hô!
ˆð Ð)Ø(:ˆNÔ%Ø Ð,Ø'<ˆNÔ$Ø Ð,Ø'<ˆNÔ$Ø&Ð2Ø-HˆNÔ*à0LÔ0@ÀÓ0LØ%Ø/ô1
÷ +
Ð ð ×!Ñ! *Ó-Ð5Ø-/Ð˜zÑ*ØBZ×BdÑBdÐ˜:Ñ&Ð'>Ñ?ô 	 ×9Ñ9Ð:LÔMà!Ð!ð+
ús   ‚CDÃDÃADrL  Ú
updated_kvc           
   ƒ   ó|  K  — ddl m} ddlm}	 | j                  €i | _        | j                  j                  d«      }
|
�½t        |
t        «      r­ ||
¬«      }|€d|v r||_        |€d|v r||_	        |€d	|v r||_
        |€d
|v r||_        |€d|_         t        |	«      ||¬«      ƒ d{  –—† }t        j                  d|j                   |||«       |j                  d«      €i |d<   |j                   |d   d<   n%t"        j%                  | |||||||¬«      ƒ d{  –—† }t"        j'                  |«       |S 7 ŒŒ7 Œ­w)zÒUpsert team member budget table with provided limits.

        A field the caller explicitly sent as null is written as null, so a
        team can keep a member budget while dropping its reset period.
        r   rp  ©Úupdate_budgetNr]  ©rê   rd  re  rf  rg  rt  ztUpdated team member budget table: %s, with team_member_budget=%s, team_member_rpm_limit=%s, team_member_tpm_limit=%srÎ   ©rl  rm  rî   rd  re  rf  rg  rn  )ru  r!   rv  rƒ  rÎ   r{  r_  r¡   rÝ   ry  rz  rÊ   Úbudget_reset_atrõ   r   Úinforê   r\  r  r|  )rL  rî   r€  rd  re  rf  rg  rn  r!   rƒ  r]  r}  Ú
budget_rows                r�   Úupsert_team_member_budget_tablez7TeamMemberBudgetHandler.upsert_team_member_budget_table%  s�  è ø€ õ  	:õ	
ð ×ÑÐ&Ø"$ˆJÔà'1×':Ñ':×'>Ñ'>Ð?VÓ'WÐØ Ð,´Ð<QÔSVÔ1Wá$4Ð?TÔ$UˆNà!Ð-Ð1EÐI^Ñ1^Ø,>�Ô)Ø$Ð0Ð4KÐOdÑ4dØ+@�Ô(Ø$Ð0Ð4KÐOdÑ4dØ+@�Ô(Ø*Ð6Ð:WÐ[pÑ:pØ1L�Ô.Ø.Ð6Ø59�NÔ2à&EÔ&6°}Ó&EØ)Ø"3ô'÷ !ˆJô !×%Ñ%ð GØ×$Ñ$Ø"Ø%Ø%ôð �~‰~˜jÓ)Ð1Ø)+�
˜:Ñ&Ø>H×>RÑ>RˆJ�zÑ"Ð#:Ò;ô  7×VÑVØØ#-Ø"3Ø#5Ø&;Ø&;Ø,GØ&;ð  Wó 	 ÷ 	ˆJô 	 ×9Ñ9¸*ÔEØÐð;!øð 	ús%   ‚B)D<Â+D8Â,A0D<ÄD:ÄD<Ä:D<Ú	data_dictc                 ó”   — | j                  dd«       | j                  dd«       | j                  dd«       | j                  dd«       y)z.Remove team member fields from data dictionaryrd  Nrg  re  rf  )ra  )rŠ  s    r�   r|  z1TeamMemberBudgetHandler._clean_team_member_fieldsl  s@   € ð 	�‰Ð*¨DÔ1Ø�‰Ð3°TÔ:Ø�‰Ð-¨tÔ4Ø�‰Ð-¨tÕ4rœ   rG   c              ƒ   óp  K  — ddl m} ddlm} | j                  €i | _        | j                  j                  d«      }|�^t        |t        «      rN ||¬«      }d|v rd|_        d|v rd|_	        d|_
        d	|v rd|_        d
|v rd|_         |||¬«      ƒ d{  –—†  t        j                  |«       |S 7 Œ­w)z=Clear explicitly-nulled fields on the team member budget row.r   rp  r‚  Nr]  r„  rd  rg  re  rf  rt  )ru  r!   rv  rƒ  rÎ   r{  r_  r¡   rÝ   rÊ   r†  ry  rz  r\  r|  )rL  rî   r€  rn  r!   rƒ  r]  r}  s           r�   Úclear_team_member_budget_fieldsz7TeamMemberBudgetHandler.clear_team_member_budget_fieldst  sÙ   è ø€ õ 	:õ	
ð ×ÑÐ&Ø"$ˆJÔà'1×':Ñ':×'>Ñ'>Ð?VÓ'WÐØ Ð,´Ð<QÔSVÔ1WÙ$4Ð?TÔ$UˆNØ#Ð'<Ñ<Ø,0�Ô)Ø,Ð0EÑEØ15�Ô.Ø15�Ô.Ø&Ð*?Ñ?Ø+/�Ô(Ø&Ð*?Ñ?Ø+/�Ô(ÙØ)Ø"3ô÷ ð ô
 	 ×9Ñ9¸*ÔEØÐðús   ‚BB6ÂB4ÂB6r•   rÙ   r]  r$  c              ƒ   óª  K  — |syt        |«      j                  d| i¬«      ƒ d{  –—† }|D �ch c]  }|j                  ’Œ }}g }|D ]L  }t        |t        «      r|j                  d«      n|j                  }|€Œ3||vsŒ8|j                  | ||dœ«       ŒN |rWt        |«      j                  |d¬«      ƒ d{  –—†  t        j                  dt        |«      t        | «      t        |«      «       t        |«      j                  | dd	œd
|i¬«      ƒ d{  –—† }	|	r+t        j                  d|	t        | «      t        |«      «       yy7 �Œ!c c}w 7 Œ–7 Œ<­w)aø  
        Ensure every team member has a TeamMembership row linked to the
        team_member_budget.

        Called after team_member_budget is set/updated on a team. Creates
        rows for members who don't have one, and populates budget_id on
        existing rows where it is NULL. Rows with a non-NULL budget_id
        are left untouched, which preserves per-member overrides but also
        means rows pointing to a prior team-default budget_id are not
        migrated to the new one.
        Nr•   ©Úwherer¯   )r•   r¯   rê   T)rl  Úskip_duplicatesz9Backfilled %d team_memberships for team %s with budget %s)r•   rê   rê   ©r�  rl  zNPopulated budget_id on %d existing team_memberships for team %s with budget %s)r-  Ú	find_manyr¯   r_  râ   r{  ÚappendÚcreate_manyr   r‡  ÚlenrG  Úupdate_many)
r•   rÙ   r]  r$  Úexisting_membershipsÚmÚexisting_user_idsÚmissingr¯   Úupdateds
             r�   Ú#backfill_team_member_budget_entriesz;TeamMemberBudgetHandler.backfill_team_member_budget_entries˜  sw  è ø€ ñ$ "Øô -@ÀÓ,N×,XÑ,XÐ`iÐkrÐ_sÐ,XÓ,t×&tÐØ7KÖ#L°! A§I£IÐ#LÐÐ#Lð
 ˆØ#ò 		ˆAÜ*4°Q¼Ô*=�a—e‘e˜IÔ&À1Ç9Á9ˆGØÑ" wÐ6GÒ'GØ—‘à#*Ø#*Ø%:ñõð		ñ Ü% mÓ4×@Ñ@ØØ $ð Aó ÷ ð ô !×%Ñ%ØKÜ�G“Ü! 'Ó*Ü!Ð"7Ó8ô	ô  3°=ÓA×MÑMØ%°DÑ9ØÐ4Ð5ð  Nó  
÷ 
ˆñ Ü ×%Ñ%Ø`ØÜ! 'Ó*Ü!Ð"7Ó8õ	ð ðK 'uûÚ#Lð$øð
úsK   ‚$E¦E§E¯E
Á8EÁ;EÂ 8EÂ8EÂ9AEÄEÄ3EÅ
EÅE)NNNN)r–   r—   r˜   r  r`  Ústaticmethodrâ   rc  rã   r™   r¡   rÕ   rk  Ú	frozensetr2   rÆ   rG   ÚAbstractSetr  rÍ   r‰  r|  Úsetr�  r   r1   r»   rs   r�  r›   rœ   r�   r\  r\  É  s‡  „ ÙRð $>Ð àð$°T¸D±[ð $ÀTò $ó ð$ð à+/Ø,0Ø,0Ø26ñ	
Ø! D™Lð
à" T™zð
ð  # T™zð
ð &)¨4¡Zð	
ð
 
ò
ó ð
ð  ð
 ,0Ø,0Ø,0Ø26Ù2;³+ñ9"ØÐ2Ñ2ð9"à ð9"ð *ð9"ð " D™Lð	9"ð
  # T™zð9"ð  # T™zð9"ð &)¨4¡Zð9"ð  +¨3Ñ/ð9"ð 
ò9"ó ð9"ðv ð
 ,0Ø,0Ø,0Ø26Ù2;³+ñDØ"ðDà)ðDð ðDð " D™Lð	Dð
  # T™zðDð  # T™zðDð &)¨4¡ZðDð  +¨3Ñ/ðDð 
òDó ðDðL ð5¨Tð 5°dò 5ó ð5ð ð!Ø"ð!à+ð!ð ð!ð  #ð	!ð
 
ò!ó ð!ðF ð@Øð@à$ V¨d°3¸°;Ñ.?Ñ%?Ñ@ð@ð  #ð@ð $ð	@ð
 
ò@ó ñ@rœ   r\  Úfieldc                 ó
  — t         j                  }|€yt        |t        «      r|j	                  | «      }nt        || d«      }|€yt        |t        «      r(|D �cg c]  }t        |d«      r|j                  n|‘Œ c}S |S c c}w )zó
    Returns a default value for the given field from litellm.default_team_params config.
    Returns None if no default is configured.

    For list fields containing enums (e.g. team_member_permissions), converts enum values to strings.
    Nr¢   )	ÚlitellmÚdefault_team_paramsr_  râ   r{  ÚgetattrÚlistÚhasattrr¢   )r¢  Údefault_paramsr¢   Úvs       r�   Ú_get_default_team_paramr«  Ü  s€   € ô $×7Ñ7€NØÐØÜ�.¤$Ô'Ø×"Ñ" 5Ó)‰ä˜¨¨tÓ4ˆØ€}Øä�%œÔØ?DÖE¸!œ7 1 gÔ.�—’°AÑ5ÒEÐEØ€Lùò Fs   Á!B r•   c                 ót   — t         j                  €ydt         j                  v r| t         j                  d   v S y)NFÚavailable_teams)r¤  Údefault_internal_user_params©r•   rî   s     r�   Ú_is_available_teamr°  ò  s9   € Ü×+Ñ+Ð3ØØœG×@Ñ@Ñ@Øœ'×>Ñ>Ð?PÑQÐQÐQØrœ   Úteam_idsr¯   c              ƒ   óô   K  — dd|ii}|�d|gi|d<   t        | «      j                  |ddi¬«      ƒ d{  –—† }g }|D ]4  }|j                  t        j                  |j                  «       «      «       Œ6 |S 7 ŒA­w)z)Get all team memberships for a given userr•   ÚinNr¯   Úlitellm_budget_tableT©r�  Úinclude)r-  r“  r”  r+   rM  r¹   )r$  r±  r¯   Ú	where_objÚteam_membershipsÚreturned_tmÚtms          r�   Úget_all_team_membershipsr»  ú  s¢   è ø€ ð
 :CÀTÈ8ÐDTÐ8U€IØÐØ $ w iÐ0ˆ	�)Ñô %8¸Ó$F×$PÑ$PØØ'¨Ð.ð %Qó %÷ Ðð
 8:€KØò SˆØ×ÑÔ1×@Ñ@ÀÇÁÃÓQÕRðSð Ððús   ‚2A8´A6µAA8Úteamsrl  Úentity_rpm_limitÚentity_tpm_limitÚentity_model_rpm_limit_dictÚentity_model_tpm_limit_dictÚentity_typec                 óª  — 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                  rf|j                  j                  dd«      �J|j                  j                  di «      j                  «       D ]  \  }}|	j                  |d«      |z   |	|<   Œ |j                  sŒ‚|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 team is allocating model specific limits.
    Raises an error if we're overallocating.
    Úmodel_rpm_limitNÚmodel_tpm_limitr   é�  úAllocated RPM limit=ú + Team RPM limit=ú is greater than ú RPM limit=rS  úAllocated TPM limit=ú + Team TPM limit=ú TPM limit=)r¦  rÎ   r{  Úitemsr   )r¼  rl  r½  r¾  r¿  rÀ  rÁ  rÃ  rÄ  Úmodel_specific_rpm_limitÚmodel_specific_tpm_limitÚteamÚmodelry  rz  Úentity_model_specific_rpm_limitÚentity_model_specific_tpm_limits                    r�   Ú!_check_team_model_specific_limitsrÔ    sú  € ô % TÐ+<¸dÓCò Ø6:·m²mˆ�‰×ÑÐ+¨TÔ2Èð ô % TÐ+<¸dÓCò Ø6:·m²mˆ�‰×ÑÐ+¨TÔ2Èð ð Ð ?Ð#:Øð 79ÐØ68Ðàò eˆØ�=Š=˜TŸ]™]×.Ñ.Ð/@À$ÓGÐSØ$(§M¡M×$5Ñ$5Ð6GÈÓ$L×$RÑ$RÓ$Tò eÑ ��yØ2J×2NÑ2NÈuÐVWÓ2XÐ[dÑ2dÐ(¨Ò/ðeà�=‹=˜TŸ]™]×.Ñ.Ð/@À$ÓGÑSØ$(§M¡M×$5Ñ$5Ð6GÈÓ$L×$RÑ$RÓ$Tò 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ÐYkÐluÐkvð  wHð  ITð  HUð  U`ð  aqð  `rð  sôð ò -Ø2M×2QÑ2QÐRWÓ2XÐ/â3Ø0×4Ñ4°U¸AÓ>ÀÑJÐMlÓlä'Ø$'Ø!5Ð6N×6RÑ6RÐSXÐZ[Ó6\Ð5]Ð]oÐpyÐozð  {Lð  MXð  LYð  Ydð  eDð  dEð   Fôð ð	ð" Ð"Ø /× 5Ñ 5Ó 7ò 	ÑˆE�9ØÐ+Ð0H×0LÑ0LÈUÐTUÓ0VÐYbÑ0bÐeuÒ0uÜ#Ø #Ø1Ð2J×2NÑ2NÈuÐVWÓ2XÐ1YÐYkÐluÐkvð  wHð  ITð  HUð  U`ð  aqð  `rð  sôð ò -Ø2M×2QÑ2QÐRWÓ2XÐ/â3Ø0×4Ñ4°U¸AÓ>ÀÑJÐMlÓlä'Ø$'Ø!5Ð6N×6RÑ6RÐSXÐZ[Ó6\Ð5]Ð]oÐpyÐozð  {Lð  MXð  LYð  Ydð  eDð  dEð   Fôð ñ	ð #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)zx
    Generic function to check if a team is allocating rpm/tpm limits.
    Raises an error if we're overallocating.
    Nr   c              3   óN   K  — | ]  }|j                   €Œ|j                   –— Œ y ­wr¥   )rz  ©Ú.0rÐ  s     r�   ú	<genexpr>z-_check_team_rpm_tpm_limits.<locals>.<genexpr>f  ó   è ø€ Ò[¨tÀÇÁÑ@Z˜DŸN�NÑ[ùó   ‚%”%c              3   óN   K  — | ]  }|j                   €Œ|j                   –— Œ y ­wr¥   )ry  r×  s     r�   rÙ  z-_check_team_rpm_tpm_limits.<locals>.<genexpr>g  rÚ  rÛ  rÅ  rÊ  rË  rÈ  rÌ  rS  rÆ  rÇ  rÉ  )r–  Úsumrz  r   ry  )r¼  rl  r½  r¾  rÁ  Úallocated_tpmÚallocated_rpms          r�   Ú_check_team_rpm_tpm_limitsrà  Z  s#  € ð ÐœS ›Z¨!š^ÜÑ[°uÔ[Ó[ˆÜÑ[°uÔ[Ó[‰àˆØˆð 	�‰Ð"ØÐ(Ø�N‰N˜]Ñ*Ð-=Ò=äØØ)¨-¨Ð8JÈ4Ï>É>ÐJZÐZkÐlwÐkxð  yDð  EUð  DVð  Wô
ð 	
ð
 	�‰Ð"ØÐ(Ø�N‰N˜]Ñ*Ð-=Ò=äØØ)¨-¨Ð8JÈ4Ï>É>ÐJZÐZkÐlwÐkxð  yDð  EUð  DVð  Wô
ð 	
ð >ð )ð 	#rœ   Ú	org_tablec           	      ó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 team is allocating model specific limits. If so, raise an error if we're overallocating.
    NrÃ  rÄ  Úorganization)r¼  rl  r½  r¾  r¿  rÀ  rÁ  )r´  ry  rz  rÎ   r{  rÔ  )r¼  rá  rl  r½  r¾  r¿  rÀ  s          r�   Ú$check_org_team_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)zu
    Check if the organization team is allocating rpm/tpm limits. If so, raise an error if we're overallocating.
    Nrã  )r¼  rl  r½  r¾  rÁ  )r´  ry  rz  rà  )r¼  rá  rl  r½  r¾  s        r�   Úcheck_org_team_rpm_tpm_limitsræ  ¢  sW   € ð ÐØÐà×%Ñ%Ð1Ø$×9Ñ9×CÑCÐØ$×9Ñ9×CÑCÐäØØØ)Ø)Ø"örœ   c              ƒ   ó¨  K  — |j                   �…| j                  �y| j                  j                   �c|j                   | j                  j                   kD  r@t        ddd|j                   › d| j                  j                   › d| j                  › �i¬«      ‚|j                  �Št        | j                  «      dkD  rrt        j                  j                  | j                  v rnK|j                  D ]<  }|| j                  vsŒt        ddd	|› d
| j                  › d| j                  › �i¬«      ‚ |j                  �…| j                  �y| j                  j                  �c|j                  | j                  j                  kD  r@t        ddd|j                  › d| j                  j                  › d| j                  › �i¬«      ‚|j                  �…| j                  �y| j                  j                  �c|j                  | j                  j                  kD  r@t        ddd|j                  › d| j                  j                  › d| j                  › �i¬«      ‚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        |«      j                  d| j                  i¬«      ƒ d{  –—† }g }|D ]4  }|j!                  t#        j$                  |j'                  «       «      «       Œ6 t)        || |¬«       t+        || |¬«       y7 Œ\­w)zÐ
    Check organization team limits including:
    - Team budget vs organization's max_budget
    - Team models vs organization's allowed models
    - Guaranteed throughput limits (tpm/rpm) if applicable
    NrÅ  r  zTeam max_budget (z%) exceeds organization's max_budget (z). Organization: rS  r   zModel 'zD' not in organization's allowed models. Organization allowed models=z. Organization: zTeam tpm_limit (z$) exceeds organization's tpm_limit (zTeam rpm_limit (z$) exceeds organization's rpm_limit (Úrpm_limit_typeÚtpm_limit_typeÚguaranteed_throughputrÛ   r�  )r¼  rá  rl  )rÝ   r´  r   rÛ   r�   r–  r9   Úall_proxy_modelsr¢   rz  ry  r¦  rÎ   r{  r'  r“  r”  r,   rM  r¹   rä  ræ  )	rá  rl  r$  r™  rè  ré  r¼  Ú	team_objsrÐ  s	            r�   Ú_check_org_team_limitsrí  »  sñ  è ø€ ð 	�‰Ð#Ø×*Ñ*Ð6Ø×*Ñ*×5Ñ5ÐAØ�O‰O˜i×<Ñ<×GÑGÒGäØàÐ,¨T¯_©_Ð,=Ð=bÐcl÷  dBñ  dB÷  dMñ  dMð  cNð  N_ð  `i÷  `yñ  `yð  _zð  {ðô
ð 	
ð ‡{�{Ð¤3 y×'7Ñ'7Ó#8¸1Ò#<ä×-Ñ-×3Ñ3°y×7GÑ7GÑGØà—[‘[ò �Ø˜I×,Ñ,Ò,Ü'Ø$'à# w¨q¨cÐ1uÐv÷  wGñ  wGð  vHð  HXð  Yb÷  Yrñ  Yrð  Xsð  &tð ôð ðð 	�‰Ð"Ø×*Ñ*Ð6Ø×*Ñ*×4Ñ4Ð@Ø�N‰N˜Y×;Ñ;×EÑEÒEäØàÐ+¨D¯N©NÐ+;Ð;_Ð`i×`~Ñ`~÷  aIñ  aIð  `Jð  J[ð  \e÷  \uñ  \uð  [vð  wðô
ð 	
ð 	�‰Ð"Ø×*Ñ*Ð6Ø×*Ñ*×4Ñ4Ð@Ø�N‰N˜Y×;Ñ;×EÑEÒEäØàÐ+¨D¯N©NÐ+;Ð;_Ð`i×`~Ñ`~÷  aIñ  aIð  `Jð  J[ð  \e÷  \uñ  \uð  [vð  wðô
ð 	
ô $ DÐ*:¸DÓAò Ø59·]²]ˆ�‰×ÑÐ*¨DÔ1Èð ô $ DÐ*:¸DÓAò Ø59·]²]ˆ�‰×ÑÐ*¨DÔ1Èð ð Ð0Ò0°^ÐG^Ò5^Øô
 " -Ó0×:Ñ:Ø  )×";Ñ";Ð<ð ;ó ÷ €Eð
 13€IØò NˆØ×ÑÔ*×9Ñ9¸$¿/¹/Ó:KÓLÕMðNô )ØØØõô
 "ØØØöðús   ‚C:MÃ=G6MË3MË4AMc           	   ƒ   óh  K  — | j                   �}|j                  �qt        |j                  ||d¬«      ƒ d{  –—† }|�N|j                   �B| j                   |j                   kD  r)t        ddd|j                   › d|j                  › �i¬«      ‚| j
                  �`t        |j
                  «      d	kD  rH| j
                  D ]9  }||j
                  vsŒt        ddd
|j
                  › d|j                  › �i¬«      ‚ | j                  �N|j                  �B| j                  |j                  kD  r)t        ddd|j                  › d|j                  › �i¬«      ‚| j                  �P|j                  �C| j                  |j                  kD  r)t        ddd|j                  › d|j                  › �i¬«      ‚yyy7 �Œx­w)u3  
    Enforce the caller's personal limits when CREATING a standalone team.

    This validates the requested team budget / models / tpm / rpm against the
    caller's own limits, so a non-admin user cannot mint a brand-new team that
    is richer than themselves.

    Only used by /team/new for standalone teams (organization_id is None).
    /team/update does NOT call this â€” an existing team's admin is already
    authorized via _verify_team_access() and is not gated by their personal
    wallet. Org-scoped teams use _check_org_team_limits() instead.
    NF©r¯   r$  rI  Úuser_id_upsertrÅ  r  z1max budget higher than user max. User max budget=z. User role=rS  r   z6Model not in allowed user models. User allowed models=z
. User id=z/tpm limit higher than user max. User tpm limit=z/rpm limit higher than user max. User rpm limit=)	rÝ   r¯   rQ   r   rV  r�   r–  rz  ry  )rl  rî   r$  rI  Úuser_objr™  s         r�   Ú_check_user_team_limitsrò  "  s@  è ø€ ð& ‡�Ð"Ð'8×'@Ñ'@Ð'LÜ /Ø%×-Ñ-Ø'Ø1Ø ô	!
÷ 
ˆð Ð H×$7Ñ$7Ð$CÈÏÉÐZb×ZmÑZmÒHmÜØàÐPÐQY×QdÑQdÐPeÐeqð  sD÷  sNñ  sNð  rOð  Pðôð ð ‡{�{Ð¤3Ð'8×'?Ñ'?Ó#@À1Ò#DØ—‘ò 	ˆAØÐ)×0Ñ0Ò0Ü#Ø #àÐ#YÐZk×ZrÑZrÐYsÐs}ð  P÷  Xñ  Xð  ~Yð  "Zðôð ð	ð 	�‰Ð"Ø×'Ñ'Ð3Ø�N‰NÐ.×8Ñ8Ò8äØàÐJÐK\×KfÑKfÐJgÐgsð  uF÷  uPñ  uPð  tQð  Rðô
ð 	
ð 	�‰Ð"Ø×'Ñ'Ð3Ø�N‰NÐ.×8Ñ8Ò8äØàÐJÐK\×KfÑKfÐJgÐgsð  uF÷  uPñ  uPð  tQð  Rðô
ð 	
ð 9ð 4ð 	#ðQ
ûs   ‚5F2·F/¸BF2ÃC"F2Úexisting_team_max_budgetc           	      ó6  — |j                   t        j                  k(  ry|€ydt        | dd«      xs
 t	        «       v }|r| j
                  €t        ddd|› d�i¬«      ‚| j
                  �0| j
                  |kD  r t        ddd	|› d
| j
                  › d�i¬«      ‚yy)aÙ  
    Restrict who can grow a standalone team's spend ceiling on /team/update.

    A team admin (already authorized via _verify_team_access) may keep or lower
    the team budget, but only a proxy admin may grow it - by raising max_budget
    above the team's current value or by removing the cap (setting it to None).
    Setting a finite budget on a team that has no cap is a restriction and is
    allowed. Org-scoped teams are governed by _check_org_team_limits().
    NrÝ   Úmodel_fields_seté“  r  zMOnly a proxy admin can remove a team's max_budget. Team's current max_budget=ú.rS  zLOnly a proxy admin can raise a team's max_budget. Team's current max_budget=z, requested=)rV  r0   rW  r¦  r¡  rÝ   r   )rl  rî   ró  Úbudget_explicitly_sets       r�   Ú#_check_team_budget_update_authorityrù  j  s   € ð ×"Ñ"Ô&6×&BÑ&BÒBØØÐ'Øà#/´G¸DÐBTÐVZÓ4[Ò4dÔ_bÓ_dÐ#eÐÙ §¡Ð!8ÜØàÐhð  jBð  iCð  CDð  Eðô
ð 	
ð ‡�Ð" t§¡Ð9QÒ'QÜØàÐgð  iAð  hBð  BNð  OS÷  O^ñ  O^ð  N_ð  _`ð  aðô
ð 	
ð (RÐ"rœ   Úgeneral_settingsc                 ó~   — | j                   €y| j                  t        j                  k7  ry|j	                  d«      duS )NFTÚ%disable_auto_add_proxy_admin_to_teams)r¯   rV  r0   rW  r{  )rî   rú  s     r�   Ú_should_auto_add_team_creatorrý  �  sC   € ð × Ñ Ð(ØØ×"Ñ"Ô&6×&BÑ&BÒBØØ×ÑÐ GÓHÐPTÐTÐTrœ   z	/team/newzteam management)ÚtagsÚ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)ÚdescriptionÚhttp_requestÚlitellm_changed_byc              ƒ   ó¨  ‡K  — 	 ddl m}m} ddlm}m}m}m}	m}
m	} |
€t        dddi¬«      ‚| 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¬«      ‚| j                  �Jt        j                  | j                  «      r| j                  dk  rt        d	dd| j                  › �i¬«      ‚t!        | j"                  «       t!        | j$                  «       | j                  �O| j                  �C| j                  | j                  k\  r*t        d	dd| j                  › d| j                  › d�i¬«      ‚t'        | d‰d¬«       t)        | d‰d¬«       t+        |
«      j-                  «       ƒ d{  –—† }|r|j/                  |¬«      rt        dd¬«      ‚| j0                  €#t3        t5        j6                  «       «      | _        no| j0                  t8        k(  rt        d	ddt8        › d�i¬«      ‚|
j;                  | j0                  dd¬«      ƒ d{  –—† }|�t        d	dd| j0                  › d�i¬«      ‚| j<                  €"t?        d«      }tA        |t2        «      r|| _        dD ]?  }tC        | |d«      �Œ|dk7  s|| jD                  vsŒ%t?        |«      }|€Œ3tG        | ||«       ŒA | j                  €†tA        tH        jJ                  tL        «      rhtO        tH        jJ                  «      dkD  rLtA        tH        jJ                  d   tP        «      r+tH        jJ                  d   jS                  d«      }|�|| _        | j<                  �V|
�T	 tU        | j<                  ||
d¬ «      ƒ d{  –—† }|€t        d	d!| j<                  › �¬«      ‚tY        || |
¬"«      ƒ d{  –—†  ‰jZ                  �‰jZ                  t\        j^                  k7  r#| j<                  €ta        | ‰|
|¬#«      ƒ d{  –—†  tc        ‰|«      rPte        ˆfd$„| jf                  D «       «      }|s0| jf                  ji                  tk        d%‰jl                  ¬&«      «       to        | ‰d¬'«       tA        | jp                  tP        «      rtr        ju                  | jp                  «       tw        d(| jp                  d| j0                  | jx                  ‰¬)«      ƒ d{  –—†  d}| jz                  �¡tA        | jz                  tP        «      r‡t}        t        j€                  | jz                  «      ‰jl                  xs |	‰jl                  xs |	¬*«      }tƒ        |
«      j…                  i |j                  d¬+«      ¥«      ƒ d{  –—† }|j†                  }| j                  «       }t‰        | jŠ                  �| jŠ                  jŒ                  ndd‰jZ                  t\        j^                  k(  |
¬,«      ƒ d{  –—†  t�        ||
¬-«      ƒ d{  –—† }tr        j‘                  | j                  | j’                  | j”                  | j$                  ¬.«      rWtr        j—                  | |‰| j                  | j’                  | j”                  | j$                  | jD                  ¬/«      ƒ d{  –—† }t™        d@i |¤d0|i¤Ž}tš        D ](  }tC        | |d«      €Œt�        ||tC        | |«      ¬1«       Œ* tž        D ](  }tC        | |d«      €Œt�        ||tC        | |«      ¬1«       Œ* |j"                  �dd2lPmQ}  ||j"                  ¬3«      |_R        |j¦                  rpdd2lPmQ} g }|j¦                  D ]R  }tA        |tP        «      r|n|j©                  «       } ||d   ¬3«      j«                  «       |d4<   |ji                  |«       ŒT ||_S        g }|jf                  �|jf                  }g |_3        |j©                  d¬+«      }tC        | d5d«      }|�t­        |«      n
t­        i «      } | |d5<   |jS                  d6«      �t¯        |d6   «      |d6<   |
j±                  |¬7«      }|}!|
j²                  jµ                  «       4 ƒd{  –—† }"|"j¶                  j…                  |!t¸        ¬8«      ƒ d{  –—† }#t»        |"|#j0                  «      ƒ d{  –—† }$ddd«      ƒd{  –—†  t½        $«      ƒ d{  –—†  t¿        | j0                  |¬9«      }%tÁ        |%#|
‰|	¬:«      ƒ d{  –—†   |«       rÂ|j                  d¬+«      }&t        j€                  |&t2        ¬;«      }&tÃ        jÄ                   |tÇ        t3        t5        j6                  «       «      tÉ        jÊ                  tÌ        jÎ                  «       ||‰|	¬<«      ‰jÐ                  tÒ        jÔ                  | j0                  d=|&d¬>«	      ¬?«      «       	 |#j©                  «       S 7 �ŒP7 �Œ³7 �Œc# tV        $ r d}Y �Œow xY w7 �ŒF7 �Œý7 �Œ&7 �Œ†7 �Œ7 �Œ7 �Œr7 �Œ¨7 �Œ‚7 �Œg7 �ŒZ# 1 ƒd{  –—†7  sw Y   �ŒkxY w7 �Œ`7 �Œ4# tÖ        $ r |#jQ                  «       cY S w xY w# tÖ        $ r}'tÙ        |'«      ‚d}'~'ww xY w­w)AuC  
    Allow users to create a new team. Apply user permissions to their team.

    ðŸ‘‰ [Detailed Doc on setting team budgets](https://docs.litellm.ai/docs/proxy/team_budgets)


    Parameters:
    - team_alias: Optional[str] - User defined team alias
    - team_id: Optional[str] - The team id of the user. If none passed, we'll generate it.
    - members_with_roles: List[{"role": "admin" or "user", "user_id": "<user-id>"}] - A list of users and their roles in the team. Get user_id when making a new user via `/user/new`.
    - team_member_permissions: Optional[List[str]] - A list of routes that non-admin team members can access. example: ["/key/generate", "/key/update", "/key/delete"]
    - metadata: Optional[dict] - Metadata for team, store information for team. Example metadata = {"extra_info": "some info"}
    - model_rpm_limit: Optional[Dict[str, int]] - The RPM (Requests Per Minute) limit for this team - applied across all keys for this team.
    - model_tpm_limit: Optional[Dict[str, int]] - The TPM (Tokens Per Minute) limit for this team - applied across all keys for this team.
    - default_estimated_output_tokens: Optional[int] - Expected output tokens reserved for TPM limiting when a request omits max_tokens, for keys on this team that do not set their own. Positive integer.
    - default_estimated_output_tokens_per_model: Optional[Dict[str, int]] - Per-model override of the above. Example: {"gpt-4": 4096, "gpt-3.5-turbo": 1024}
    - mcp_rpm_limit: Optional[Dict[str, int]] - Per-MCP-server RPM limit for this team, keyed by MCP server name (alias if set, else the configured name). Example: {"github": 100, "slack": 200}. Applied across all keys for this team.
    - tpm_limit: Optional[int] - The TPM (Tokens Per Minute) limit for this team - all keys with this team_id will have at max this TPM limit
    - rpm_limit: Optional[int] - The RPM (Requests Per Minute) limit for this team - all keys associated with this team_id will have at max this RPM limit
    - rpm_limit_type: Optional[Literal["guaranteed_throughput", "best_effort_throughput"]] - The type of RPM limit enforcement. Use "guaranteed_throughput" to raise an error if overallocating RPM, or "best_effort_throughput" for best effort enforcement.
    - tpm_limit_type: Optional[Literal["guaranteed_throughput", "best_effort_throughput"]] - The type of TPM limit enforcement. Use "guaranteed_throughput" to raise an error if overallocating TPM, or "best_effort_throughput" for best effort enforcement.
    - max_budget: Optional[float] - The maximum budget allocated to the team - all keys for this team_id will have at max this max_budget
    - soft_budget: Optional[float] - The soft budget threshold for the team. If max_budget is set, soft_budget must be strictly lower than max_budget. Can be set independently if max_budget is not set.
    - budget_duration: Optional[str] - The duration of the budget for the team. Doc [here](https://docs.litellm.ai/docs/proxy/team_budgets)
    - models: Optional[list] - A list of models associated with the team - all keys for this team_id will have at most, these models. If empty, assumes all models are allowed.
    - blocked: bool - Flag indicating if the team is blocked or not - will stop all calls from keys with this team_id.
    - members: Optional[List] - Control team members via `/team/member/add` and `/team/member/delete`.
    - 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 team is allowed to use.
    - organization_id: Optional[str] - The organization id of the team. Default is None. Create via `/organization/new`.
    - model_aliases: Optional[dict] - Model aliases for the team. [Docs](https://docs.litellm.ai/docs/proxy/team_based_routing#create-team-with-model-alias)
    - guardrails: Optional[List[str]] - Guardrails for the team. [Docs](https://docs.litellm.ai/docs/proxy/guardrails)
    - policies: Optional[List[str]] - Policies for the team. [Docs](https://docs.litellm.ai/docs/proxy/guardrails/guardrail_policies)
    - disable_global_guardrails: Optional[bool] - Whether to disable global guardrails for the key.
    - object_permission: Optional[LiteLLM_ObjectPermissionBase] - team-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.
    - team_member_budget: Optional[float] - The maximum budget allocated to an individual team member.
    - team_member_budget_duration: Optional[str] - The duration of the budget for the team member. Doc [here](https://docs.litellm.ai/docs/proxy/team_budgets)
    - team_member_rpm_limit: Optional[int] - The RPM (Requests Per Minute) limit for individual team members.
    - team_member_tpm_limit: Optional[int] - The TPM (Tokens Per Minute) limit for individual team members.
    - team_member_key_duration: Optional[str] - The duration for a team member's key. e.g. "1d", "1w", "1mo"
    - allowed_passthrough_routes: Optional[List[str]] - List of allowed pass through routes for the team.
    - 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.
    - secret_manager_settings: Optional[dict] - Secret manager settings for the team. [Docs](https://docs.litellm.ai/docs/secret_managers/overview)
    - router_settings: Optional[UpdateRouterConfig] - team-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 team. Access groups define which models the team can access. Example - ["access_group_1", "access_group_2"].
    - enforced_file_expires_after: Optional[dict] - Enforced file expiration policy for the team. Keys created under this team will inherit this policy for file uploads. Example - {"anchor": "created_at", "days": 30}.
    - enforced_batch_output_expires_after: Optional[dict] - Enforced batch output file expiration policy for the team. Keys created under this team will inherit this policy for batch output files. Example - {"anchor": "created_at", "days": 30}.
    - budget_limits: Optional[list] - List of concurrent budget windows for the team. 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"}].
    - default_team_member_models: Optional[List[str]] - Default models assigned to new team members when they join this team. Must be a subset of the team's models.

    Returns:
    - team_id: (str) Unique team id - used for tracking spend across multiple keys for same team id.

    _deprecated_params:
    - admins: list - A list of user_id's for the admin role
    - users: list - A list of user_id's for the user role

    Example Request:
    ```
    curl --location 'http://0.0.0.0:4000/team/new'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
      "team_alias": "my-new-team_2",
      "members_with_roles": [{"role": "admin", "user_id": "user-1234"},
        {"role": "user", "user_id": "user-2434"}]
    }'

    ```

     ```
    curl --location 'http://0.0.0.0:4000/team/new'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
                "team_alias": "QA Prod Bot",
                "max_budget": 0.000000001,
                "budget_duration": "1d"
            }'
    ```
    r   ©Úget_audit_log_changed_byÚis_audit_logging_enabled)Ú_license_checkÚcreate_audit_log_for_updaterú  Úlitellm_proxy_admin_namer$  rI  Néô  r  úNo db connectedrS  rÅ  ú;max_budget must be a non-negative finite number. Received: úCteam_member_budget must be a non-negative finite number. Received: ú<soft_budget must be a non-negative finite number. Received: úsoft_budget (ú*) must be strictly lower than max_budget (ú)rÐ  ©rl  Úexisting_metadatarî   Úentity)Ú
team_countrö  zOLicense is over limit. Please contact support@berri.ai to upgrade your license.z	team_id 'zs' is reserved for LiteLLM UI dashboard sessions and cannot be used for a real team. Please use a different team id.Úfind_unique©r•   Ú
table_nameÚ
query_typez
Team id = z0 already exists. Please use a different team id.rÛ   )rÝ   rÊ   rz  ry  Úteam_member_permissionsrÊ   rÝ   T)Úorg_idrI  r$  Úinclude_budget_tablez+Organization not found for organization_id=©rá  rl  r$  )rl  rî   r$  rI  c              3   óP   •K  — | ]  }|j                   ‰j                   k(  –— Œ y ­wr¥   ©r¯   )rØ  Úmemberrî   s     €r�   rÙ  znew_team.<locals>.<genexpr>   s&   øè ø€ ò /Ø@F�—‘Ð"3×";Ñ";Õ;ñ/ùs   ƒ#&Úadmin)Úroler¯   ©r  Úcreate©Ú	operationrÎ   r  r•   rÈ   rî   ©Úmodel_aliasesÚ
created_byÚ
updated_byrÑ   ©Úrequested_mcp_serversÚexisting_object_permission_idÚis_proxy_adminr$  )Ú	data_jsonr$  rj  r…  rá   )Úobject_dataÚ
field_namer¢   ©Úget_budget_reset_time©rÊ   Úreset_atÚrouter_settingsrÎ   ©Údb_data)rl  r¶  )r•   r!  ©rl  Úcomplete_team_datar$  rî   r
  ©Údefault©r  rî   r
  Úcreated©	ÚidÚ
updated_atÚ
changed_byÚchanged_by_api_keyr  Ú	object_idÚactionÚupdated_valuesÚbefore_value©Úrequest_datar›   )mÚ+litellm.proxy.management_helpers.audit_logsr  r  Úlitellm.proxy.proxy_serverr  r	  rú  r
  r$  rI  r   rÝ   ÚmathÚisfiniterd  rß   rb   rÊ   rg  rT   rS   r'  ÚcountÚis_team_count_over_limitr•   r¡   r   rw  r   Úget_datarÛ   r«  r_  r¦  rõ  Úsetattrr¤  Údefault_team_settingsr§  r–  râ   r{  rN   rH   rí  rV  r0   rW  rò  rý  ri  rÙ   r”  r1   r¯   rZ   rÎ   r\  rc  ro   rÈ   r)  r(   rÔ   Údumpsr1  r%  rA  rk   Úobject_permissionÚmcp_serversrj   rk  re  rf  r  r,   r'   r]   r&   Ú)litellm.proxy.common_utils.timezone_utilsr4  r†  Úbudget_limitsr¹   Ú	isoformatr   rV   Újsonify_team_objectÚdbr)  r
  r#  rh   rg   r@   Ú_add_team_members_to_teamÚasyncioÚcreate_taskr$   r   Únowr   ÚutcÚapi_keyr/   ÚTEAM_TABLE_NAMErC  ru   )(rl  r  rî   r  r  r  r  r	  rú  r
  r$  rI  Útotal_teamsÚ_existing_team_idÚdefault_organization_idr¢  Údefault_valueÚdefault_budgetrá  Úcreating_user_in_listÚ	_model_idÚlitellm_modeltableÚ
model_dictr0  r;  r4  Úinitialized_windowsÚwindowÚwrÙ   Úcomplete_team_data_dictÚrouter_settings_valueÚrouter_settings_jsonÚteam_creation_datar)  rH  Úaffected_access_groupsÚteam_member_add_requestÚ_updated_valuesÚes(     `                                     r�   Únew_teamrw  ›  sÿ
  øè ø€ ðBW+÷	
÷	
÷ 	
ð Ð Ü¨C¸ÐBSÐ8TÔUÐUð �?‰?Ð&´·±¸d¿o¹oÔ0NÐRV×RaÑRaÐdeÒReÜØØÐ#^Ð_c×_nÑ_nÐ^oÐ!pÐqôð ð ×"Ñ"Ð.Ü—‘˜d×5Ñ5Ô6¸$×:QÑ:QÐTUÒ:UäØàÐbÐcg×czÑczÐb{Ð|ðôð ð ×ÑÐ'´·±¸t×?OÑ?OÔ1PÐTX×TdÑTdÐghÒThÜØØÐ#_Ð`d×`pÑ`pÐ_qÐ!rÐsôð ô
 	! ×!5Ñ!5Ô6Ü  ×!AÑ!AÔBà×ÑÐ'Ø�‰Ð*à×#Ñ# t§¡Ò6Ü'Ø$'à# }°T×5EÑ5EÐ4FÐFpÐqu÷  rAñ  rAð  qBð  BCð  &Dð ôð ô 	6ØØ"Ø/Øõ		
ô 	9ØØ"Ø/Øõ		
ô $,¨MÓ#:×#@Ñ#@Ó#B×BˆÙ˜>×BÑBÈkÐBÔZÜØØhôð ð
 �<‰<ÐÜœtŸz™z›|Ó,ˆD�Là�|‰|œzÒ)Ü#Ø #à 9¬Z¨Lð  9lð  "mðôð ð .;×-CÑ-CØŸ™°ÀMð .Dó .÷ (Ðð !Ð,Ü#Ø #Ø# z°$·,±,°Ð?oÐ%pÐqôð ð
 ×ÑÐ'Ü-DÐEVÓ-WÐ#ÜÐ1´3Ô7Ø'>�Ô$ð

ò 	8ˆEô �t˜U DÓ)Ñ1ØÐ*Ò*¨e¸4×;PÑ;PÒ.Pä 7¸Ó >�Ø Ñ,Ü˜D %¨Õ7ð	8ð  �?‰?Ð"äœ7×8Ñ8¼$Ô?Üœ×5Ñ5Ó6¸Ò:Üœw×<Ñ<¸QÑ?ÄÔFä(/×(EÑ(EÀaÑ(H×(LÑ(LÈ\Ó(Z�Ø!Ð-Ø&4�D”Oð ×ÑÐ+°Ð0Ið!Ü"0Ø×/Ñ/Ø'9Ø"/Ø)-ô	#÷ �	ð Ð Ü#Ø #ØHÈ×I]ÑI]ÐH^Ð_ôð ô
 )Ø#ØØ+ô÷ ð ð ×'Ñ'Ð/Ð3D×3NÑ3NÔRb×RnÑRnÒ3nð ×#Ñ#Ð+Ü-ØØ&7Ø"/Ø'9ô	÷ ð ô )Ð):Ð<LÔMÜ+.ó /ØJN×JaÑJaô/ó ,Ð!ñ )Ø×'Ñ'×.Ñ.¬v¸7ÐL]×LeÑLeÔ/fÔgä3°DÐ:KÐTZÕ[ä�d—m‘m¤TÔ*Ü#×FÑFÀtÇ}Á}ÔUä2ØØ—]‘]Ø"Ø—L‘LØ—‘Ø/ô
÷ 	
ð 	
ð ˆ	Ø×ÑÐ)¬j¸×9KÑ9KÌTÔ.RÜ(:Ü"Ÿj™j¨×);Ñ);Ó<Ø,×4Ñ4ÒPÐ8PØ,×4Ñ4ÒPÐ8Pô)Ðô
 '0°Ó&>×&EÑ&EÐFtÐI[×I`ÑI`ÐnrÐI`ÓIsÐFtÓ&u× uˆJà"Ÿ™ˆIà—I‘I“Kˆ	ô @ØIM×I_ÑI_ÐIk 4×#9Ñ#9×#EÒ#EÐquØ*.Ø,×6Ñ6Ô:J×:VÑ:VÑVØ'ô	
÷ 	
ð 	
ô 1ØØ'ô
÷ 
ˆ	ô
 #×7Ñ7Ø#×6Ñ6Ø"&×"<Ñ"<Ø"&×"<Ñ"<Ø(,×(HÑ(Hð	 8ô 
ô 6×UÑUØØ#,Ø"3Ø#'×#:Ñ#:Ø&*×&@Ñ&@Ø&*×&@Ñ&@Ø,0×,LÑ,LØ&*×&;Ñ&;ð Vó 	÷ 	ˆIô %6ñ %
Øñ%
àò%
Ðô Gò 	ˆEÜ�t˜U DÓ)Ñ5Ü*Ø 2Ø$Ü! $¨Ó.öð	ô ?ò 	ˆEÜ�t˜U DÓ)Ñ5Ü*Ø 2Ø$Ü! $¨Ó.öð	ð ×-Ñ-Ð9ÝWá1FØ 2× BÑ Bô2ÐÔ.ð
 ×+Ò+ÝWà)+ÐØ,×:Ñ:ò .�Ü(¨´Ô6‘F¸F×<MÑ<MÓ<O�Ù 5ÀaÐHYÑFZÔ [× eÑ eÓ g��*‘Ø#×*Ñ*¨1Õ-ð.ð 0CÐÔ,ð ,.ÐØ×0Ñ0Ð<Ø!3×!FÑ!FÐØ46ÐÔ1à"4×"?Ñ"?ÈTÐ"?Ó"RÐô (/¨tÐ5FÈÓ'MÐà1FÐ1RŒJÐ,Ô-ÔXbÐceÓXfð 	ð 6JÐÐ 1Ñ2à"×&Ñ& zÓ2Ð>Ü2GÐH_Ð`jÑHkÓ2lÐ# JÑ/à"/×"CÑ"CÐLcÐ"CÓ"dÐØ:QÐð !×#Ñ#×&Ñ&Ó(÷ 	oð 	o¨BØEG×EYÑEY×E`ÑE`Ø'Ü,ð Faó F÷ @ˆHô 3YÐY[Ð]e×]mÑ]mÓ2n×,nÐ"÷	o÷ 	oô -Ð-CÓD×DÐDô *>Ø—L‘LØ%ô*
Ðô (Ø(Ø'Ø'Ø/Ø%=ô
÷ 	
ð 	
ñ $Ô%Ø0×5Ñ5À4Ð5ÓHˆOä"Ÿj™j¨Ä#ÔFˆOä×ÑÙ+Ü!2ÜœtŸz™z›|Ó,Ü#+§<¡<´·±Ó#=Ù#;Ø/AØ.?Ø5Mô$ð
 ,=×+DÑ+DÜ#4×#DÑ#DØ"&§,¡,Ø(Ø'6Ø%)ô"ôôð(	#Ø×&Ñ&Ó(Ð(ðc Cùð$(ùð\úô -ò !Ø “	ð!úðùðùð&	
ùð" !vùð	
ùð
ùð	ùðV	oùð@ùð -oùð	où÷ 	o÷ 	oò 	oúð 	Eùð	
úôF ò 	#Ø—=‘=“?Ò"ð	#ûäò +Ü'¨Ó*Ð*ûð+üsÑ  ƒk…G*j6 Ç/h?Ç0Bj6 ÊiÊA#j6 Ë4j6 Ìj6 ÌB/j6 Ïi Ï"iÏ#i Ï'-j6 ÐiÐAj6 Ñ iÑ!Cj6 Ô:i Ô;B"j6 ×i#×A/j6 Ùi&Ùj6 Ù"i)Ù#Bj6 Û:i,Û;)j6 Ü%0j6 ÝE1j6 ãi/ãj6 ã%i;ã0i2ã1i;äi5äi;äj6 äi8äj6 ä1jä2.j6 å jå!Cj6 è/j è>kè?j6 éj6 éi éiéj6 éiéj6 éj6 é j6 é#j6 é&j6 é)j6 é,j6 é/j6 é2i;é5i;é8j6 é;jêjêjê		j6 êj6 êj3ê0j6 ê1kê2j3ê3j6 ê6	kê?k
ë
këkÚexisting_team_rowr€  r
  c              ƒ   óÂ  K  — ddl m}m} | j                  d¬«      }t        j                  |t
        ¬«      }t        j                  |t
        ¬«      }	t        j                   |t        t        t        j                  «       «      t        j                  t        j                  «       ||||¬«      |j                  t         j"                  |d|	|¬«	      ¬	«      «       y
­w)a´  
    Create an audit log entry for team update operations.

    Args:
        existing_team_row: The team row before the update
        updated_kv: Dictionary of updated key-value pairs
        team_id: The ID of the team being updated
        litellm_changed_by: Optional header indicating who made the change
        user_api_key_dict: User API key authentication details
        litellm_proxy_admin_name: Name of the proxy admin
    r   )r	  r  TrÑ   r<  r>  rœ  r@  rI  N)rK  r	  r  rÔ   rT  r¡   r]  r^  r$   r   rw  r   r_  r   r`  ra  r/   rb  )
rx  r€  r•   r  rî   r
  r	  r  Ú_before_valueÚ_after_values
             r�   Ú_create_team_update_audit_logr|  V  s­   è ø€ ÷&ð
 &×*Ñ*¸Ð*Ó=€MÜ—J‘J˜}´cÔ:€MÜ#Ÿz™z¨*¼cÔB€Lä×ÑÙ#Ü*Ü”t—z‘z“|Ó$Ü#Ÿ<™<¬¯©Ó5Ù3Ø'9Ø&7Ø-Eôð
 $5×#<Ñ#<Ü,×<Ñ<Ø!Ø Ø+Ø*ôô	
õùs   ‚CCrá   c              ƒ   ó  K  — |}| j                   �òt        | j                   t        «      rØt        t	        j
                  | j                   «      |j                  xs ||j                  xs |¬«      }|€6t        |«      j                  i |j	                  d¬«      ¥¬«      ƒ d{  –—† }nMt        |«      j                  d|ii |j	                  d¬«      ¥i |j	                  d¬«      ¥dœ¬«      ƒ d{  –—† }|j                  }|S 7 Œ`7 Œ­w)	z4
    Upsert model table and return the model id
    Nr(  TrÑ   ©rl  rA  )Úupdater%  r’  )r)  r_  râ   r(   rÔ   rT  r¯   r1  r%  ÚupsertrA  )rl  rá   r$  rî   r
  ri  rj  rk  s           r�   Ú_update_model_tabler�  ‡  s  è ø€ ð €IØ×ÑÐ%¬*°T×5GÑ5GÌÔ*NÜ$6ÜŸ*™* T×%7Ñ%7Ó8Ø(×0Ñ0ÒLÐ4LØ(×0Ñ0ÒLÐ4Lô%
Ðð
 ÐÜ(¨Ó7×>Ñ>ÐDrÐGY×G^ÑG^ÐlpÐG^ÓGqÐDrÐ>Ós×s‰Jä(¨Ó7×>Ñ>Ø˜XÐ&àLÐ!3×!8Ñ!8ÀdÐ!8Ó!KÐLØLÐ!3×!8Ñ!8ÀdÐ!8Ó!KÐLñð  ?ó  ÷ ˆJð —M‘Mˆ	àÐð tøðús%   ‚B"D	Â$DÂ%AD	Ã2DÃ3D	ÄD	rÐ  rã  c              ƒ   óH  K  — |j                   r$|j                   D �ch c]  }|j                  ’Œ c}n	t        «       }| j                  D ]—  }|j                  €Œ|j                  t        j
                  j                  k(  rŒ8|j                  |v rŒG|j                  €ŒT	 t        t        |j                  t        j                  ¬«      |j                  |¬«      ƒ d{  –—†  Œ™ yc c}w 7 Œ# t        $ r+}t        j                  d|j                  |«       Y d}~ŒÑd}~ww xY w­w)a(  
    When moving a team to an org, ensure all team members are also org members.

    For SSO/Entra setups without SCIM, users join teams automatically on login but
    are never explicitly added to organizations. This silently upserts missing members
    rather than blocking the team move.
    N)r¯   r#  )r!  rÛ   r$  z@_auto_add_team_members_to_organization: skipping user_id=%s - %s)Úmembersr¯   r¡  rÙ   r:   Údefault_user_idr¢   rÛ   rc   r3   r0   ÚINTERNAL_USERrC  r   Údebug)rÐ  rã  r$  r™  Úorg_member_idsr!  rv  s          r�   Ú&_auto_add_team_members_to_organizationrˆ  ©  s  è ø€ ð JV×I]ÒI]°×0DÑ0DÖE¨1˜QŸY›YÓEÔcfÓch€NØ×)Ñ)ò ˆØ�>‰>Ð!ØØ�>‰>Ô0×@Ñ@×FÑFÒFØØ�>‰>˜^Ñ+ØØ×'Ñ'Ð/Øð	Ü,Ü Ø"ŸN™NÜ)×7Ñ7ôð !-× <Ñ <Ø+ô÷ ñ ñùò Fðùô ò 	Ü ×&Ñ&ØRØ—‘Ø÷ñ ûð	üsL   ‚D"�C$°A-D"Â>C+ÃC)ÃC+Ã!D"Ã)C+Ã+	DÃ4!DÄD"ÄDÄD"rÛ   Ú
llm_routerz'prisma_models.LiteLLM_OrganizationTablec              ƒ   óB  K  — |€'t        ddt        j                  j                  i¬«      ‚t	        |«      j                  d| iddddœ¬«      ƒ d{  –—† }|€t        d	dd
| › �i¬«      ‚|duxr |j                  t        j                  k(  }t        j                  |j                  «       «      }t        t        j                  |j                  «       «      |||¬«       |r7t        t        j                  |j                  «       «      ||¬«      ƒ d{  –—†  |S 7 ŒÉ7 Œ­w)aÊ  
    Fetch and validate an organization for team update operations.

    Args:
        organization_id: The organization ID to fetch
        existing_team_row: The existing team row being updated
        llm_router: The LLM router instance
        prisma_client: The Prisma database client

    Returns:
        The organization row from the database

    Raises:
        HTTPException: If llm_router is None, organization not found, or validation fails
    Nr  r  rS  rÛ   T)r´  rƒ  r¼  rµ  é”  z/Organization not found, passed organization_id=)rÐ  rã  r‰  r/  )rÐ  rã  r$  )r   r"   Úno_llm_routerr¢   r3  r  rV  r0   rW  r*   rM  r¹   Úvalidate_team_org_changer,   rˆ  )rÛ   rx  r‰  r$  rî   Úorganization_rowr/  rã  s           r�   Úfetch_and_validate_organizationr�  Ð  s8  è ø€ ð, ÐÜ¨°WÔ>O×>]Ñ>]×>cÑ>cÐ4dÔeÐeä$+¨MÓ$:×$FÑ$FØ  /Ð2Ø)-¸$ÈÑNð %Gó %÷ Ðð
 ÐÜØØÐNÈÐN_Ð`Ðaô
ð 	
ð
 '¨dÐ2ÒrÐ7H×7RÑ7RÔVf×VrÑVrÑ7r€NÜ>×MÑMÐN^×NiÑNiÓNkÓl€LÜÜ×-Ñ-Ð.?×.JÑ.JÓ.LÓMØ!ØØ%õ	ñ Ü4Ü"×1Ñ1Ð2C×2NÑ2NÓ2PÓQØ%Ø'ô
÷ 	
ð 	
ð Ðð7øð*	
ús%   ‚ADÁDÁCDÄDÄDÄDr/  c           	      óê  — | j                   |j                   k(  ryt        |j                  «      dkD  ryt        j                  j
                  |j                  v rnR| j                  �t        | j                  «      dk(  rt        dddi¬«      ‚| j                  D ]  }t        |||¬«       Œ | j                  ry|j                  rm|j                  j                  rW| j                  |j                  j                  kD  r4t        ddd| j                  › d	|j                  j                  › d
�i¬«      ‚|s¨| j                  D �cg c]  }|j                  ‘Œ }}|j                  r$|j                  D �cg c]  }|j                  ‘Œ c}ng }|D �cg c]'  }||vsŒ|t        j                  j
                  k7  sŒ&|‘Œ) }}t        |«      dkD  rt        ddd|› d�i¬«      ‚| j                  ry|j                  rm|j                  j                  rW| j                  |j                  j                  kD  r4t        ddd| j                  › d|j                  j                  › d
�i¬«      ‚| j                   ry|j                  rm|j                  j                   rW| j                   |j                  j                   kD  r4t        ddd| j                   › d|j                  j                   › d
�i¬«      ‚yc c}w c c}w c c}w )aa  
    Validate that a team can be moved to an organization.

    - The org must have access to the team's models
    - The team budget cannot be greater than the org max_budget
    - For non-proxy-admins: all team members must already be org members
    - The team's tpm/rpm limit must be less than the org's tpm/rpm limit

    Proxy admins bypass the membership check and instead trigger auto-add of
    missing members (handled by the caller). This supports SSO/Entra setups
    where org membership tables are empty but proxy admins still need to group
    teams under orgs for budget/model governance.
    Tr   rö  r  zeCannot move team to organization. Team has access to all proxy models, but the organization does not.rS  )rÑ  Ú
org_objectr‰  z6Cannot move team to organization. Team has max_budget z4 that is greater than the organization's max_budget r÷  z3Cannot move team to organization. Team has user_id z* that is not a member of the organization.z5Cannot move team to organization. Team has tpm_limit z3 that is greater than the organization's tpm_limit z5Cannot move team to organization. Team has rpm_limit z3 that is greater than the organization's rpm_limit )rÛ   r–  r�   r9   rë  r¢   r   rK   rÝ   r´  rÙ   r¯   rƒ  r:   r„  rz  ry  )	rÐ  rã  r‰  r/  rÑ  r™  Úteam_membersÚorg_membersÚ
not_in_orgs	            r�   r�  r�    sQ  € ð, ×Ñ˜|×;Ñ;Ò;Øô ˆ<×ÑÓ !Ò#Ü×-Ñ-×3Ñ3°|×7JÑ7JÑJØØ�[‰[Ð ¤C¨¯©Ó$4¸Ò$9ÜØàð  Eðôð ð Ÿ™ò �Ü$ØØ+Ø)öðð 	�ŠØ×-Ò-Ø×-Ñ-×8Ò8Ø�O‰O˜l×?Ñ?×JÑJÒJäØàÐQÐRV×RaÑRaÐQbð  cWð  Xd÷  Xyñ  Xy÷  XDñ  XDð  WEð  EFð  Gðô
ð 	
ñ Ø26×2IÑ2IÖJ¨Q˜qŸy›yÐJˆÐJØJV×J^ÒJ^°×1EÑ1EÖF¨A˜aŸi›iÓFÐdfˆà#ö
Ø q°Ò';ÀÔEX×EhÑEh×EnÑEnÓ@nŠAð
ˆ
ð 
ô ˆz‹?˜QÒÜØàÐRÐS]ÐR^ð  _Ið  Jðôð ð 	�ŠØ×-Ò-Ø×-Ñ-×7Ò7Ø�N‰N˜\×>Ñ>×HÑHÒHäØàÐPÐQU×Q_ÑQ_ÐP`ð  aTð  Ua÷  Uvñ  Uv÷  U@ñ  U@ð  TAð  ABð  Cðô
ð 	
ð 	�ŠØ×-Ò-Ø×-Ñ-×7Ò7Ø�N‰N˜\×>Ñ>×HÑHÒHäØàÐPÐQU×Q_ÑQ_ÐP`ð  aTð  Ua÷  Uvñ  Uv÷  U@ñ  U@ð  TAð  ABð  Cðô
ð 	
ð ùòM KùÚFùò
s   ÅK&Å0K+Æ	K0ÆK0Æ4K0z/team/update)rþ  rÿ  c           
   ƒ   óZ  K  — 	 ddl m} ddlm}m}m}m}m}	 |€'t        ddt        j                  j                  i¬«      ‚| j                  €t        ddd	i¬«      ‚t        j                  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¬«      ‚| j&                  �Jt!        j"                  | j&                  «      r| j&                  dk  rt        ddd| j&                  › �i¬«      ‚t)        | j*                  «       t)        | j,                  «       t/        t1        |«      «      j3                  d| j                  i¬«      ƒ d{  –—† }
|
€t        ddd| j                  › �i¬«      ‚t5        t7        j8                  |
j;                  «       «      |¬«      ƒ d{  –—†  t=        |
dd«      }t?        | tA        |tB        «      r|nd|d¬«       tE        | tA        |tB        «      r|nd|d¬«       tG        | |d¬«       | j&                  �U| j                  �| j                  n|
j                  }|�/| j&                  |k\  r t        ddd| j&                  › d|› d�i¬«      ‚| j                  �wtI        t=        |
dd«      «      }| j&                  �| j&                  n|}|�EtA        |tJ        tL        f«      r/| j                  |k  r t        ddd| j                  › d|› d�i¬«      ‚| jN                  �ðtQ        | jN                  «      dkD  rØt=        |
dd«      }| jN                  |k7  r™|jR                  tT        jV                  j                  k7  rr|jX                  rSt[        |«      j]                  |jX                  | jN                  tT        j^                  j                  dœ¬«      ƒ d{  –—† ng }|st        ddd i¬«      ‚ta        | jN                  |
|||¬!«      ƒ d{  –—†  n+| jN                  �tQ        | jN                  «      dk(  rd| _'        tI        | jN                  �| jN                  n|
jN                  «      }|�@tA        |tb        «      r0|�.te        ||	|¬"«      ƒ d{  –—† }|�tg        || |¬#«      ƒ d{  –—†  |€ti        | ||
j                  ¬$«       | jk                  d%¬&«      }tA        |jm                  d«      tB        «      rtn        jq                  |d   «       d|v r°tA        |
jr                  tB        «      r@|
jr                  ju                  «       D ��ci c]  \  }}|tn        jv                  vr||“Œ c}}nd}ty        d'|jm                  d«      || j                  | jz                  �| jz                  n|
jz                  |¬(«      ƒ d{  –—†  t}        | |«       d)D �ch c]  }||v r|’Œ
 }}|rötn        j                  | j$                  | j€                  | j‚                  | j,                  ¬)«      rµtn        j…                  |
||| j$                  | j€                  | j‚                  | j,                  |¬*«      ƒ d{  –—† }|jm                  d«      xs i jm                  d+«      }|r{|
j†                  rotn        j‰                  | j                  |
j†                  ||¬,«      ƒ d{  –—†  n9|r"tn        j‹                  |
|||¬-«      ƒ d{  –—† }ntn        j�                  |«       | jŽ                  �et‘        | jŽ                  j’                  |
j”                  |jR                  tT        jV                  k(  |¬.«      ƒ d{  –—†  t—        ||
¬/«      ƒ d{  –—† }t™        |¬0«       |jm                  d«      �t›        |d   «      |d<   d1|v r:|j�                  d1«       tŸ        | |
j                   |||¬2«      ƒ d{  –—† }|�||d3<   d4|v r|d4   �t£        |d4   «      |d4<   |j¥                  |¬5«      }|}t§        |«      j©                  d| j                  i|d%d%d6œ¬7«      ƒ d{  –—† }|�|j                  €t        ddd8|› �i¬«      ‚t        jª                  d9|j                  «       t­        ||j                  ¬:«      ƒ d{  –—†  t¯        ||	|¬;«      ƒ d{  –—†   |«       r#t±        |
|| j                  |||¬<«      ƒ d{  –—†  |j                  |d=œS 7 �Œ„7 �Œ37 �Œ/7 �Œý7 �Œ}7 �Œhc c}}w 7 �ŒZc c}w 7 �Œ³7 �ŒO7 �Œ.7 �Œ¿7 �Œ­7 �ŒK7 Œä7 Œ‡7 Œs7 ŒK# t²        $ r}tµ        |«      ‚d}~ww xY w­w)>a+  
    Use `/team/member_add` AND `/team/member/delete` to add/remove new team members

    You can now update team budget / rate limits via /team/update

    Parameters:
    - team_id: str - The team id of the user. Required param.
    - team_alias: Optional[str] - User defined team alias
    - team_member_permissions: Optional[List[str]] - A list of routes that non-admin team members can access. example: ["/key/generate", "/key/update", "/key/delete"]
    - metadata: Optional[dict] - Metadata for team, store information for team. Example metadata = {"team": "core-infra", "app": "app2", "email": "ishaan@berri.ai" }
    - tpm_limit: Optional[int] - The TPM (Tokens Per Minute) limit for this team - all keys with this team_id will have at max this TPM limit
    - rpm_limit: Optional[int] - The RPM (Requests Per Minute) limit for this team - all keys associated with this team_id will have at max this RPM limit
    - max_budget: Optional[float] - The maximum budget allocated to the team - all keys for this team_id will have at max this max_budget
    - soft_budget: Optional[float] - The soft budget threshold for the team. If max_budget is set (either in the request or existing), soft_budget must be strictly lower than max_budget. Can be set independently if max_budget is not set.
    - budget_duration: Optional[str] - The duration of the budget for the team. Doc [here](https://docs.litellm.ai/docs/proxy/team_budgets)
    - models: Optional[list] - A list of models associated with the team - all keys for this team_id will have at most, these models. If empty, assumes all models are allowed.
    - prompts: Optional[List[str]] - List of prompts that the team is allowed to use.
    - blocked: bool - Flag indicating if the team is blocked or not - will stop all calls from keys with this team_id.
    - 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).
    - organization_id: Optional[str] - The organization id of the team. Default is None. Create via `/organization/new`.
    - model_aliases: Optional[dict] - Model aliases for the team. [Docs](https://docs.litellm.ai/docs/proxy/team_based_routing#create-team-with-model-alias)
    - guardrails: Optional[List[str]] - Guardrails for the team. [Docs](https://docs.litellm.ai/docs/proxy/guardrails)
    - policies: Optional[List[str]] - Policies for the team. [Docs](https://docs.litellm.ai/docs/proxy/guardrails/guardrail_policies)
    - disable_global_guardrails: Optional[bool] - Whether to disable global guardrails for the key.
    - object_permission: Optional[LiteLLM_ObjectPermissionBase] - team-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.
    - team_member_budget: Optional[float] - The maximum budget allocated to an individual team member.
    - team_member_budget_duration: Optional[str] - The duration of the budget for the team member. Doc [here](https://docs.litellm.ai/docs/proxy/team_budgets)
    - team_member_rpm_limit: Optional[int] - The RPM (Requests Per Minute) limit for individual team members.
    - team_member_tpm_limit: Optional[int] - The TPM (Tokens Per Minute) limit for individual team members.
    - team_member_key_duration: Optional[str] - The duration for a team member's key. e.g. "1d", "1w", "1mo"
    - allowed_passthrough_routes: Optional[List[str]] - List of allowed pass through routes for the team.
    - model_rpm_limit: Optional[Dict[str, int]] - The RPM (Requests Per Minute) limit per model for this team. Example: {"gpt-4": 100, "gpt-3.5-turbo": 200}
    - model_tpm_limit: Optional[Dict[str, int]] - The TPM (Tokens Per Minute) limit per model for this team. Example: {"gpt-4": 10000, "gpt-3.5-turbo": 20000}
    - default_estimated_output_tokens: Optional[int] - Expected output tokens reserved for TPM limiting when a request omits max_tokens, for keys on this team that do not set their own. Positive integer.
    - default_estimated_output_tokens_per_model: Optional[Dict[str, int]] - Per-model override of the above. Example: {"gpt-4": 4096, "gpt-3.5-turbo": 1024}
    - mcp_rpm_limit: Optional[Dict[str, int]] - Per-MCP-server RPM limit for this team, keyed by MCP server name (alias if set, else the configured name). Example: {"github": 100, "slack": 200}. Applied across all keys for this team.
    Example - update team TPM Limit
    - 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.
    - secret_manager_settings: Optional[dict] - Secret manager settings for the team. [Docs](https://docs.litellm.ai/docs/secret_managers/overview)
    - router_settings: Optional[UpdateRouterConfig] - team-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 team. Access groups define which models the team can access. Example - ["access_group_1", "access_group_2"].
    - enforced_file_expires_after: Optional[dict] - Enforced file expiration policy for the team. Keys created under this team will inherit this policy for file uploads. Example - {"anchor": "created_at", "days": 30}.
    - enforced_batch_output_expires_after: Optional[dict] - Enforced batch output file expiration policy for the team. Keys created under this team will inherit this policy for batch output files. Example - {"anchor": "created_at", "days": 30}.
    - budget_limits: Optional[list] - List of concurrent budget windows for the team. 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"}].
    - default_team_member_models: Optional[List[str]] - Default models assigned to new team members when they join this team. Must be a subset of the team's models.

    ```
    curl --location 'http://0.0.0.0:4000/team/update'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data-raw '{
        "team_id": "8d916b1c-510d-4894-a334-1c16a93344f5",
        "tpm_limit": 100
    }'
    ```

    Example - Update Team `max_budget` budget
    ```
    curl --location 'http://0.0.0.0:4000/team/update'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data-raw '{
        "team_id": "8d916b1c-510d-4894-a334-1c16a93344f5",
        "max_budget": 10
    }'
    ```
    r   )r  )r
  r‰  r$  rJ  rI  Nr  r  rS  rÅ  úNo team id passed inz/team/update - %sr  r  r  r•   r�  r‹  úTeam not found, passed team_id=rY  rÎ   rÐ  r  r$  r  r  r  rß   zmax_budget (z-) must be strictly greater than soft_budget (rÛ   )r¯   rÛ   rV  rö  zgRelocating a team to a different organization requires PROXY_ADMIN or org-admin of the destination org.)rÛ   rx  r‰  r$  rî   )r  rI  r$  r  )rl  rî   ró  T©Úexclude_unsetr  r&  rj  )rL  rî   r€  rd  re  rf  rg  rn  r]  )r•   rÙ   r]  r$  )rL  rî   r€  rn  r,  )r0  rx  )r€  r)  )rl  rá   r$  rî   r
  rá   r7  r8  ©r"  rU  ©r�  rl  r¶  zTeam doesn't exist. Got=z$Successfully updated team - %s, info©r$  r•   rN  )rx  r€  r•   r  rî   r
  )r•   rl  )[rK  r  rL  r
  r‰  r$  rJ  rI  r   r"   Údb_not_connected_errorr¢   r•   r   r†  rÝ   rM  rN  rd  rß   rb   rÊ   rg  ræ   r~   r  rZ  r,   rM  r¹   r¦  rT   r_  râ   rS   rZ   r¦   r™   rã   rÛ   r–  rV  r0   rW  r¯   r5  r“  Ú	ORG_ADMINr�  r¡   rN   rí  rù  rÔ   r{  r\  rc  rÎ   rÍ  r`  ro   rÈ   Ú_set_budget_reset_atrk  re  rf  r‰  rÙ   r�  r�  r|  rU  rk   rV  rÄ   Úhandle_update_object_permissionr_   rV   ra  r�  rá   r   rZ  r'  r  r‡  ri   rO  r|  rC  ru   )rl  r  rî   r  r  r
  r‰  r$  rJ  rI  rx  Ú_existing_team_metadataÚmax_budget_to_checkÚexisting_soft_budgetÚsoft_budget_to_checkÚcurrent_org_idÚcaller_membershipsÚorg_id_to_checkrá  r€  rb  r¢   Ústored_metadatar¢  Ú_team_member_fields_in_requestÚ_backfill_budget_idri  Úteam_update_datarH  rv  s                                 r�   Úupdate_teamr¬  n  sg
  è ø€ ð\C+ÝX÷	
õ 	
ð Ð ÜØØÔ!2×!IÑ!I×!OÑ!OÐPôð ð
 �<‰<ÐÜ¨C¸ÐBXÐ8YÔZÐZÜ×"Ñ"Ð#6¸Ô=ð �?‰?Ð&´·±¸d¿o¹oÔ0NÐRV×RaÑRaÐdeÒReÜØØÐ#^Ð_c×_nÑ_nÐ^oÐ!pÐqôð ð ×"Ñ"Ð.Ü—‘˜d×5Ñ5Ô6¸$×:QÑ:QÐTUÒ:UäØàÐbÐcg×czÑczÐb{Ð|ðôð ð ×ÑÐ'´·±¸t×?OÑ?OÔ1PÐTX×TdÑTdÐghÒThÜØØÐ#_Ð`d×`pÑ`pÐ_qÐ!rÐsôð ô
 	! ×!5Ñ!5Ô6Ü  ×!AÑ!AÔBä".¬~¸mÓ/LÓ"M×"YÑ"YØ˜dŸl™lÐ+ð #Zó #
÷ 
Ðð Ð$ÜØØÐ#BÀ4Ç<Á<À.Ð!QÐRôð ô "Ü&×5Ñ5Ð6G×6RÑ6RÓ6TÓUØ/ô
÷ 	
ð 	
ô
 29Ð9JÈJÐX\Ó1]ÐÜ5ØÜ9CÐD[Ô]aÔ9bÑ5ÐhlØ/Øõ		
ô 	9ØÜ9CÐD[Ô]aÔ9bÑ5ÐhlØ/Øõ		
ô 	4°DÐ:KÐTZÕ[à×ÑÐ'Ø59·_±_Ð5P $§/¢/ÐVg×VrÑVrÐØ"Ð.Ø×#Ñ#Ð':Ò:Ü'Ø$'à# }°T×5EÑ5EÐ4FÐFpð  rEð  qFð  FGð  &Hð ôð ð �?‰?Ð&Ü2<¼WÐEVÐXeÐgkÓ=lÓ2mÐ Ø>B×>NÑ>NÐ>Z¨$×*:Ò*:Ð`tÐ Ø#Ð/´JÐ?SÔVYÔ[`ÐUaÔ4bØ—?‘?Ð&:Ò:Ü'Ø$'à# |°D·O±OÐ3DÐDqð  sGð  rHð  HIð  &Jð ôð ð ×ÑÐ+´°D×4HÑ4HÓ0IÈAÒ0Mô %,Ð,=Ð?PÐRVÓ$WˆNà×$Ñ$¨Ò6Ø%×/Ñ/Ô3C×3OÑ3O×3UÑ3UÒUð )×0Ò0ô -¨]Ó;×EÑEà'8×'@Ñ'@Ø/3×/CÑ/CÜ)9×)CÑ)C×)IÑ)Iñð Fó ÷ ð ð ð #ñ *Ü'Ø$'à#ð!3ð ô	ð 	ô 2Ø $× 4Ñ 4Ø"3Ø%Ø+Ø"3ô÷ ñ ð ×!Ñ!Ð-´#°d×6JÑ6JÓ2KÈqÒ2Pà#'ˆDÔ ô *4Ø$(×$8Ñ$8Ð$DˆD× Ò ÐJ[×JkÑJkó*
ˆð Ð&¬:°oÄsÔ+KÐP]ÐPiÜ%3Ø&Ø#5Ø+ô&÷  ˆIð
 Ð$Ü,Ø'ØØ"/ô÷ ð ð Ð"Ü/ØØ"3Ø):×)EÑ)Eõð —Y‘Y¨T�YÓ2ˆ
ô �j—n‘n ZÓ0´$Ô7Ü#×FÑFÀzÐR\ÑG]Ô^à˜Ñ#ô Ð/×8Ñ8¼$Ô?ð '8×&@Ñ&@×&FÑ&FÓ&H÷á"˜˜UØÔ"9×"VÑ"VÑVð ˜‘Jôð ð ô 7Ø"Ø#Ÿ™¨
Ó3Ø"1ØŸ™Ø.2¯o©oÐ.I˜4Ÿ?š?ÐO`×OkÑOkØ"3ô÷ ð ô 	˜T :Ô.ðö	1
àð ˜
Ñ"ò ð	1
Ð&ð 	1
ñ *Ô.E×.ZÑ.ZØ#×6Ñ6Ø"&×"<Ñ"<Ø"&×"<Ñ"<Ø(,×(HÑ(Hð	 /[ô /
ô  7×VÑVØ,Ø"3Ø%Ø#'×#:Ñ#:Ø&*×&@Ñ&@Ø&*×&@Ñ&@Ø,0×,LÑ,LØ&Dð  Wó 	 ÷ 	ˆJð +5¯.©.¸Ó*DÒ*JÈ×)OÑ)OÐPgÓ)hÐÙ"Ð'8×'KÒ'KÜ-×QÑQØ ŸL™LØ'8×'KÑ'KØ*=Ø"/ð	 Ró ÷ ñ ñ ,Ü6×VÑVØ,Ø"3Ø%Ø&Dð	  Wó  ÷ ‰Jô $×=Ñ=¸jÔIð ×!Ñ!Ð-ÜCØ&*×&<Ñ&<×&HÑ&HØ.?×.TÑ.TØ0×:Ñ:Ô>N×>ZÑ>ZÑZØ+ô	÷ ð ô  ?Ø$Ø"3ô ÷ ˆJô 	 ¨:Õ6à�>‰>˜*Ó%Ð1Ü%:¸:ÀjÑ;QÓ%RˆJ�zÑ"à˜jÑ(Ø�N‰N˜?Ô+Ü%8ØØ*×3Ñ3Ø+Ø"3Ø)Aô&÷  ˆIð Ð$Ø)2�
˜:Ñ&ð  
Ñ*¨zÐ:KÑ/LÐ/XÜ,6°zÐBSÑ7TÓ,UˆJÐ(Ñ)à"×6Ñ6¸zÐ6ÓJˆ
Ø8BÐÜ (¨Ó 7× >Ñ >Ø˜dŸl™lÐ+Ø!ð
 (,Ø%)ñð !?ó 
!
÷ 

ˆð Ð˜x×/Ñ/Ð7ÜØØÐ#;¸H¸:Ð!FÐGôð ô
 	×!Ñ!Ð"HÈ(×JZÑJZÔ[Ü/¸mÐU]×UeÑUeÔf×fÐfÜ"ØØ1Ø/ô
÷ 	
ð 	
ñ $Ô%Ü/Ø"3Ø%ØŸ™Ø#5Ø"3Ø)Aô÷ ð ð $×+Ñ+°XÑ>Ð>ðk
ùð	
ùðtùð,ùð  ùðûó0ðûò	1
ð"	ùðùðùðùðùð ùð 

øð& 	gøð	
øðùô ò +Ü'¨Ó*Ð*ûð+üs~  ‚f+„Gf ÇeÇAf È%eÈ&Hf Ð,eÐ-4f Ñ!eÑ"Bf Ó$e!Ó%f Ó<e$Ó=B"f Öe'Ö>Af Øe-Øf Ø(e0Ø5Bf Ûe5ÛA&f Ü)e8Ü*#f Ýe;ÝA1f Þ?e>ß f ßfßA$f à9fà:A(f â"fâ#Af äf	äf äfä)f åfåf åf+åf åf åf åf å!f å$f å'f å0f å8f å;f å>f æf æf æf æ	f æf æf æ	f(æf#æ#f(æ(f+z/team/{team_id}c           	   ƒ   ó   K  — ddl m} 	 |€'t        ddt        j                  j
                  i¬«      ‚|j                  �/|j                  | k7  r t        ddd|j                  › d	| › d
�i¬«      ‚|j                  ddh¬«      }d|v rst        |«      j                  d| i¬«      ƒ d{  –—† }|€t        ddd| › �i¬«      ‚t        |j                  t        «      r|j                  ni }t        ||d   «      |d<   t        j                  d| i|¥«      }	t!        |	|||¬«      ƒ d{  –—† }
|
d   S 7 Œ‡7 Œ# t"        $ r}t%        |«      ‚d}~ww xY w­w)a5  
    Partially update a team using RFC 7386 JSON Merge Patch semantics.

    `team_id` is taken from the path; a `team_id` in the body is accepted only when it
    matches. `metadata` is merged with the team's stored metadata rather than replacing
    it: an omitted key is preserved, `key: null` deletes it, and any other value
    overwrites (recursing into nested objects). Every other field behaves exactly like
    `POST /team/update` (omitted preserves, a value overwrites). Returns the full
    updated team.

    ```
    curl --location --request PATCH 'http://0.0.0.0:4000/team/8d916b1c-510d-4894-a334-1c16a93344f5'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data-raw '{
        "metadata": {"cost_center": "1234", "deprecated_key": null}
    }'
    ```
    r   r&  Nr  r  rS  rÅ  zteam_id in body (z") does not match team_id in path (r  Tr•   )r™  ÚexcluderÎ   r�  r‹  r—  )rl  r  rî   r  rl  )rL  r$  r   r"   r�  r¢   r•   r¹   r'  r  r_  rÎ   râ   rW   rF   rM  r¬  rC  ru   )r•   rl  r  rî   r  r$  Úpatch_fieldsrx  r  Úupdate_requestÚresultrv  s               r�   Ú
patch_teamr²  	  s‘  è ø€ õJ 9ð#+ØÐ ÜØØÔ!2×!IÑ!I×!OÑ!OÐPôð ð
 �<‰<Ð#¨¯©¸Ò(?ÜØØÐ#4°T·\±\°NÐBdÐelÐdmÐmnÐ!oÐpôð ð
 #Ÿo™o¸DÈ9È+˜oÓVˆà˜Ñ%Ü-5°mÓ-D×-PÑ-PÐXaÐcjÐWkÐ-PÓ-l×'lÐØ Ð(Ü#Ø #Ø#Ð'FÀwÀiÐ%PÐQôð ô ?IÐIZ×IcÑIcÔeiÔ>jÐ 1× :Ò :ÐprÐÜ'=Ð>OÐQ]Ð^hÑQiÓ'jˆL˜Ñ$ä 1× @Ñ @À)ÈWÐAeÐXdÐAeÓ fˆä)ØØ%Ø/Ø1ô	
÷ 
ˆð �f‰~Ðð# (møð
ùô ò +Ü'¨Ó*Ð*ûð+üsN   ‚EŠBD2 Â&D.Â'A=D2 Ä$D0Ä%D2 Ä-EÄ.D2 Ä0D2 Ä2	EÄ;EÅEÅEc                 óÄ  — | j                   �ddlm}  || j                   ¬«      }||d<   nd|v r
|d   €d|d<   | j                  �›t	        | j                  «      dkD  r‚ddlm} g }| j                  D ]R  }t        |t        «      r|n|j                  «       } ||d   ¬«      j                  «       |d<   |j                  |«       ŒT t        j                  |«      |d<   yyy)	zASet budget_reset_at in updated_kv if budget_duration is provided.Nr   r3  r5  r†  rÊ   r6  rX  )rÊ   rW  r4  rX  r–  r_  râ   r¹   rY  r”  rÔ   rT  )rl  r€  r4  r6  rl  rm  rn  s          r�   rŸ  rŸ  O	  sé   € à×ÑÐ'ÝSá/À×@TÑ@TÔUˆØ(0ˆ
Ð$Ò%Ø	˜jÑ	(¨ZÐ8IÑ-JÐ-RØ(,ˆ
Ð$Ñ%à×ÑÐ%¬#¨d×.@Ñ.@Ó*AÀAÒ*EÝSà%'ÐØ×(Ñ(ò 	*ˆFÜ$ V¬TÔ2‘¸×8IÑ8IÓ8KˆAÙ1À!ÐDUÑBVÔW×aÑaÓcˆAˆj‰MØ×&Ñ& qÕ)ð	*ô '+§j¡jÐ1DÓ&Eˆ
�?Ò#ð +FÐ%rœ   r0  c              ƒ   ó˜   K  — ddl m} t        | |j                  |¬«      ƒ d{  –—† }|�|| d<   t	        j
                  d|«       | S 7 Œ#­w)a  
    Handle the update of object permission for a team.

    - IF there's no object_permission_id, then create a new entry in LiteLLM_ObjectPermissionTable
    - IF there's an object_permission_id, then update the entry in LiteLLM_ObjectPermissionTable
    r   r&  )r0  r.  r$  NrÄ   z updated object_permission_id: %s)rL  r$  rl   rÄ   r   r†  )r0  rx  r$  rÄ   s       r�   r   r   d	  s]   è ø€ õ 9ô )OØØ&7×&LÑ&LØ#ô)÷ #Ðð Ð'Ø,@ˆ	Ð(Ñ)Ü×"Ñ"Ð#EÐG[Ô\àÐð#ús   ‚"A
¤A¥$A
r!  Úpremium_userc                 óD  — t        | t        «      r:| j                  dk(  r+|dur&t        dt        j
                  j                  › �«      ‚y t        | t        «      rF| D ]@  }|j                  dk(  sŒ|dusŒt        d|› dt        j
                  j                  › d�«      ‚ y y )Nr"  Tz,Assigning team admins is a premium feature. z0Assigning team admins is a premium feature. Got=z. )r_  r1   r#  Ú
ValueErrorr"   Únot_premium_userr¢   r§  )r!  rµ  r™  s      r�   Ú_check_team_member_admin_addr¹  |	  s§   € ô �&œ&Ô! f§k¡k°WÒ&<Ø˜tÑ#ÜÐKÔL]×LnÑLn×LtÑLtÐKuÐvÓwÐwð $ä	�FœDÔ	!Øò 	ˆAØ�v‰v˜Ó Ø tÒ+Ü$ØJÈ1È#ÈRÔPa×PrÑPr×PxÑPxÐOyÐy{Ð|óð ñ	ð 
"rœ   c                 ó  — | €t        dddi¬«      ‚|j                  €t        dddi¬«      ‚|j                  €t        dddi¬«      ‚	 t        |j                  |¬«       y # t        $ r}t        ddt        |«      i¬«      ‚d }~ww xY w)	Nr  r  r  rS  rÅ  r–  zNo member/members passed in)r!  rµ  )r   r•   r!  r¹  rC  r¡   )r$  rl  rµ  rv  s       r�   Úteam_call_validation_checksr»  Œ	  s™   € ð
 ÐÜ¨°WÐ>OÐ4PÔQÐQà‡|�|ÐÜ¨°WÐ>TÐ4UÔVÐVà‡{�{ÐÜ¨°WÐ>[Ð4\Ô]Ð]ðGÜ$Ø—;‘;Ø%ö	
øô ò GÜ¨°W¼cÀ!»fÐ4EÔFÐFûðGús   Á	A! Á!	BÁ*BÂBc                 ó  ‡‡— g Šdt         fˆˆfd„}t        | j                  t         «      r || j                  «       n3t        | j                  t        «      r| j                  D ]
  } ||«       Œ t        | j                  t        «      rKt	        ‰«      t	        | j                  «      k(  r*t        d‰j                  › �t        j                  dd¬«      ‚t        | j                  t         «      rft	        ‰«      dk(  rXt        d| j                  j                  › d| j                  j                  › d	‰j                  › �t        j                  dd¬«      ‚t	        ‰«      d
kD  r"t        j                  d‰j                  ‰«       yy)zË
    Check if a member already exists in the team.
    This check is done BEFORE we create/fetch the user, so it only prevents
    obvious duplicates where both user_id and user_email match exactly.
    r!  c                 ó(  •— | j                   �<‰j                  D ]-  }|j                   | j                   k(  sŒ‰j                  | «       Œ/ | j                  �=‰j                  D ]-  }|j                  | j                  k(  sŒ‰j                  | «       Œ/ y y r¥   )r¯   rÙ   r”  Ú
user_email)r!  Úexisting_memberrx  Úinvalid_team_memberss     €€r�   Ú_check_member_duplicationzDteam_member_add_duplication_check.<locals>._check_member_duplication¯	  sŒ   ø€ Ø�>‰>Ð%Ø#4×#GÑ#Gò 8�Ø"×*Ñ*¨f¯n©nÓ<Ø(×/Ñ/°Õ7ð8ð
 ×ÑÐ(Ø#4×#GÑ#Gò 8�Ø"×-Ñ-°×1BÑ1BÓBØ(×/Ñ/°Õ7ñ8ð )rœ   z0All users are already in team. Existing members=Ú400©ÚmessageÚtypeÚparamÚcodeé   z&User already in team. Member: user_id=z, user_email=z. Existing members=r   zISome users are already in team. Existing members=%s. Duplicate members=%sN)r1   r_  r!  r§  r–  r6   rÙ   r5   Úteam_member_already_in_teamr¯   r¾  r   r‡  )rl  rx  rÁ  r™  rÀ  s    `  @r�   Ú!team_member_add_duplication_checkrÊ  £	  sk  ù€ ð #%Ðð
8¬&ö 
8ô �$—+‘+œvÔ&Ù! $§+¡+Õ.Ü	�D—K‘K¤Ô	&Ø—‘ò 	)ˆAÙ% aÕ(ð	)ô �$—+‘+œtÔ$¬Ð-AÓ)BÄcÈ$Ï+É+ÓFVÒ)VÜØFÐGX×GkÑGkÐFlÐmÜ ×<Ñ<ØØô	
ð 	
ô 
�D—K‘K¤Ô	(¬SÐ1EÓ-FÈ!Ò-KÜØ<¸T¿[¹[×=PÑ=PÐ<QÐQ^Ð_c×_jÑ_j×_uÑ_uÐ^vð  wJð  K\÷  Koñ  Koð  Jpð  qÜ ×<Ñ<ØØô	
ð 	
ô 
Ð!Ó	" QÒ	&Ü×!Ñ!ØWØ×0Ñ0Ø õ	
ð 
'rœ   r;  c              ƒ   ó¨  K  — t        | dd«      t        j                  j                  k(  ryt	        | |¬«      ryt        | |¬«      ƒ d{  –—† ryt        |j                  | ¬«      s)t        dddj                  d|j                  «      i¬	«      ‚|j                  €|j                  €|j                  �t        ddd
i¬	«      ‚t        |j                  t        «      r|j                  n|j                  g}t        | dd«      }|D ]F  }t        |dd«      dk7  rt        dddi¬	«      ‚t        |dd«      }|r|r||k7  sŒ9t        dddi¬	«      ‚ y7 �Œ­w)a°  Validate if user has permission to add members to the team.

    Standard users can self-join an *available team*, but the bypass
    must not be allowed to escalate them to ``role=admin`` or to add
    other users into the team.  When access is granted via the
    available-team bypass we therefore enforce that every member in
    the request matches the caller's own ``user_id`` and is being
    added with ``role="user"``.
    rV  NrR  r¯  rö  r  úJCall not allowed. User not proxy admin OR team admin. route={}, team_id={}ú/team/member_addrS  z”Available-team self-join cannot set per-member budget or model controls (max_budget_in_team, budget_duration, allowed_models); these are admin-only.r¯   r#  ÚuserziAvailable-team self-join cannot assign 'admin' role. Only proxy/team/org admins can add admins to a team.zgAvailable-team self-join can only add the caller (user_id must match the authenticated user's user_id).)r¦  r0   rW  r¢   r\   r[   r°  r•   r   ÚformatÚmax_budget_in_teamrÊ   Úallowed_modelsr_  r!  r§  )rî   r;  rl  rƒ  Úcaller_user_idr!  Úmember_user_ids          r�   Ú%_validate_team_member_add_permissionsrÔ  Ù	  s†  è ø€ ô Ð  +¨tÓ4Ô8H×8TÑ8T×8ZÑ8ZÒZØÜÐ->ÐI[Õ\ØÜ(Ð;LÐWiÔj×jÐjØäØ"×*Ñ*Ø+õô ØàÐe×lÑlØ&Ø&×.Ñ.óðô
ð 	
ð ×ÑÐ*¨d×.BÑ.BÐ.NÐRV×ReÑReÐRqÜØàð=ðô	
ð 		
ô %/¨t¯{©{¼DÔ$A�T—[’[ÈÏÉÀ}€GÜ#Ð$5°yÀ$ÓG€NØò ˆÜ�6˜6 6Ó*¨fÒ4ÜØàðOðôð ô ! ¨°DÓ9ˆÙ¡^°~ÈÓ7WÜØàðQðôð ñðM kûs   ‚AEÁ
EÁC2EÄ>Ec              ƒ   óÆ  K  — g }g }|j                   �|j                   j                  d«      nd}| j                  }	t        |dd«      }
|	€|
r|
}	t	        | j
                  t        «      rq	 t        | j
                  | j                  |||| j                  ||	| j                  |¬«
      ƒ d{  –—† \  }}|j                  |«       |�|j                  |«       ||fS t	        | j
                  t        «      ru| j
                  D ]f  }	 t        || j                  |||| j                  ||	| j                  |¬«
      ƒ d{  –—† \  }}|j                  |«       |€ŒV|j                  |«       Œh ||fS 7 ŒÂ# t        $ r1}t        ddd| j
                  › d| j                  › d	|› �i¬
«      ‚d}~ww xY w7 Œq# t        $ r'}t        ddd|› d| j                  › d	|› �i¬
«      ‚d}~ww xY w­w)zËProcess and add new team members.

    ``tx`` is the caller's open transaction, when it has one, so the member writes run on the
    connection it already holds instead of checking out a second one.
    Nr]  Údefault_team_member_models)
Ú
new_memberrÐ  r$  rî   r
  r•   Údefault_team_budget_idrÑ  rÊ   r)  r  r  zUnable to add user - z, to team - z, for reason - rS  )rÎ   r{  rÑ  r¦  r_  r!  r1   rq   rÐ  r•   rÊ   rC  r   r”  r§  )rl  r;  r$  rî   r
  r)  Úupdated_usersÚupdated_team_membershipsrØ  Úmember_allowed_modelsÚteam_default_member_modelsÚupdated_userÚ
updated_tmrv  r™  s                  r�   Ú_process_team_membersrß  )
  s2  è ø€ ð 57€MØDFÐð EW×D_ÑD_ÐDkÐ×#Ñ#×'Ñ'Ð(?Ô@Ðquð ð
 !×/Ñ/ÐÜ(/Ð0BÐD`ÐbfÓ(gÐØÐ$Ñ)CØ :Ðä�$—+‘+œvÔ&ð	Ü-;ØŸ;™;Ø#'×#:Ñ#:Ø+Ø"3Ø)AØŸ™Ø'=Ø4Ø $× 4Ñ 4Øô.÷ (Ñ$ˆL˜*ð" 	×Ñ˜\Ô*ØÐ!Ø$×+Ñ+¨JÔ7ð2 Ð2Ð2Ð2ô1 
�D—K‘K¤Ô	&Ø—‘ò 	<ˆAðÜ1?Ø Ø'+×'>Ñ'>Ø"/Ø&7Ø-EØ ŸL™LØ+AØ#8Ø$(×$8Ñ$8Øô2÷ ,Ñ(�˜jð" × Ñ  Ô.ØÑ%Ø(×/Ñ/°
Õ;ð+	<ð. Ð2Ð2Ð2ðY(ùô ò 	ÜØØÐ#8¸¿¹¸À\ÐRV×R^ÑR^ÐQ_Ð_nÐopÐnqÐ!rÐsôð ûð	úð,ùô ò Ü#Ø #Ø#Ð'<¸Q¸C¸|ÈDÏLÉLÈ>ÐYhÐijÐhkÐ%lÐmôð ûðüsz   ‚A'G!Á*A E/ Â*E-Â+E/ Â2AG!Ä6F.Ä:F,Ä;F.ÅG!ÅG!Å-E/ Å/	F)Å8,F$Æ$F)Æ)G!Æ,F.Æ.	GÆ7"GÇGÇG!rÙ  c                 ó¼   ‡ ‡— ‰ j                   xs t        ˆ fd„|D «       d«      Š‰ j                  xs t        ˆfd„|D «       d«      }‰ j                  ‰|dœ¬«      S )a„  Return ``member`` with whichever of ``user_id`` / ``user_email`` the caller left out filled in.

    The roster entry is a snapshot, so whatever is missing here is missing for good.
    Resolution runs both ways off the user rows the add just touched: added by email
    -> stamp the user_id, added by user_id -> stamp the email. A value the caller
    supplied is never overwritten.
    c              3   ó€   •K  — | ]5  }‰j                   �'|j                   ‰j                   k(  r|j                  –— Œ7 y ­wr¥   ©r¾  r¯   )rØ  rÎ  r!  s     €r�   rÙ  z+_resolve_member_identity.<locals>.<genexpr>}
  s:   øè ø€ ò 	
àØ× Ñ Ð,°·±ÀF×DUÑDUÒ1Uð �L�Lñ	
ùs   ƒ;>Nc              3   óp   •K  — | ]-  }‰�)|j                   ‰k(  r|j                  �|j                  –— Œ/ y ­wr¥   ©r¯   r¾  )rØ  rÎ  Úresolved_user_ids     €r�   rÙ  z+_resolve_member_identity.<locals>.<genexpr>…
  s;   øè ø€ ò 	
àØÐ+°·±Ð@PÒ0PÐUY×UdÑUdÐUpð �O�Oñ	
ùs   ƒ36rä  ©r  )r¯   Únextr¾  Ú
model_copy)r!  rÙ  Úresolved_user_emailrå  s   `  @r�   Ú_resolve_member_identityrê  t
  s~   ù€ ð %Ÿn™nò ´ó	
à%ô	
ð
 	ó1Ðð "(×!2Ñ!2ò "´dó	
à%ô	
ð
 	ó7Ðð ×Ñà'Ø-ñ
ð ó ð rœ   c                 ó@   ‡ — t        ˆ fd„|j                  D «       «      S )Nc              3   óÆ   •K  — | ]X  }‰j                   d uxr |j                   ‰j                   k(  xs) ‰j                  d uxr |j                  ‰j                  k(  –— ŒZ y ­wr¥   rä  )rØ  r¿  r!  s     €r�   rÙ  z*_member_already_in_team.<locals>.<genexpr>•
  sh   øè ø€ ò ð ð 
�‰˜tÐ	#Ò	Q¨×(?Ñ(?À6Ç>Á>Ñ(Qò 	_Ø×Ñ TÐ)Ò]¨o×.HÑ.HÈF×L]ÑL]Ñ.]ó	_ñùs   ƒAA!)ri  rÙ   )r!  r;  s   ` r�   Ú_member_already_in_teamrí  ”
  s%   ø€ Üó ð  2×DÑDôó ð rœ   c              ƒ   óø   ‡‡K  — t        | j                  t        «      r| j                  fnt        | j                  «      }t        ˆfd„|D «       «      }‰j                  j                  ˆfd„|D «       «       y­w)z*Update the team's members_with_roles list.c              3   ó6   •K  — | ]  }t        |‰«      –— Œ y ­wr¥   )rê  )rØ  r™  rÙ  s     €r�   rÙ  z,_update_team_members_list.<locals>.<genexpr>¥
  s   øè ø€ Ò#jÐSTÔ$<¸QÀ×$NÑ#jùs   ƒc              3   ó<   •K  — | ]  }t        |‰«      rŒ|–— Œ y ­wr¥   )rí  )rØ  r™  r;  s     €r�   rÙ  z,_update_team_members_list.<locals>.<genexpr>ª
  s!   øè ø€ ò 1ØÔ+BÀ1ÐFXÕ+YŒñ1ùó   ƒ•N)r_  r!  r1   ÚtuplerÙ   Úextend)rl  r;  rÙ  Úrequested_membersÚresolved_memberss    ``  r�   Ú_update_team_members_liströ  œ
  sf   ùè ø€ ô % T§[¡[´&Ô9ˆ�‰‰¼uÀTÇ[Á[Ó?Qð ô $Ó#jÐXiÔ#jÓjÐð
 ×)Ñ)×0Ñ0ó 1Ø#ô1õ ùs   „A6A:zprisma_models.LiteLLM_TeamTablec           	   ƒ   ó  K  — dd| j                   › d�i}|j                  «       4 ƒd{  –—† }|j                  t        | j                   «      ƒ d{  –—†  t	        |«      j                  || j                   «      ƒ d{  –—† }|€t        d|¬«      ‚||_        t        | |||||¬«      ƒ d{  –—† \  }}	t        | ||¬«      ƒ d{  –—†  |j                  D �
cg c]  }
|
j                  «       ‘Œ }}
t        |«      j                  d	| j                   id
t        j                  |«      i¬«      ƒ d{  –—† }|€t        d|¬«      ‚ddd«      ƒd{  –—†  	fS 7 �Œ27 �Œ7 Œâ7 Œµ7 Œžc c}
w 7 Œ97 Œ# 1 ƒd{  –—†7  sw Y   Œ,xY w­w)a¢  Add team members to the team, under the team's advisory lock.

    The lock (``TEAM_ADVISORY_LOCK_SQL``, keyed on the team id) is taken first, and the
    team is re-read under it before any write, so a delete that already committed is
    visible here before this call writes anything: the user and membership writes only
    happen once the re-read proves the team is still live. /team/delete takes the same
    lock around its own sweep-and-delete, so the two can never interleave; whichever
    acquires the lock first runs to completion before the other's re-read can proceed.

    The user and membership writes run on this transaction too, not on a second
    connection from the pool: a lock waiter that needs a connection it hasn't got yet is
    a waiter that can deadlock the pool, since enough concurrent adds for one team would
    hold every connection waiting on the lock while the holder waits for a free one.
    r  zTeam=z. was deleted while this member add was runningNr‹  rS  )rl  r;  r$  rî   r
  r)  )rl  r;  rÙ  r•   rÙ   r’  )r•   r)  Ú	query_rawre   r~   Úget_members_with_roles_lockedr   rÙ   rß  rö  r¹   r+  r  rÔ   rT  )rl  r;  r$  rî   r
  Úgone_detailr)  Úlocked_membersrÙ  rÚ  r™  Ú_db_team_membersÚupdated_teams                r�   r\  r\  ¯
  s¤  è ø€ ð* )0°5¸¿¹¸ÐFtÐ1uÐ'v€KØ×ÑÓ!÷ Eð E RØ�l‰lÔ1°4·<±<Ó@×@Ð@ä&4°]Ó&C×&aÑ&aÐbdÐfj×frÑfrÓ&s× sˆØÐ!Ü¨C¸ÔDÐDØ0>ÐÔ-ä8MØØ1Ø'Ø/Ø%=Øô9
÷ 3
Ñ/ˆÐ/ô (ØØ1Ø'ô
÷ 	
ð 	
ð <N×;`Ñ;`Ö"a°a 1§<¡<¥>Ð"aÐÐ"aÜ$/°£O×$:Ñ$:Ø˜dŸl™lÐ+Ø&¬¯
©
Ð3CÓ(DÐEð %;ó %
÷ 
ˆð ÐÜ¨C¸ÔDÐD÷;E÷ Eð> ˜Ð(@Ð@Ð@ð?EùØ@ùà søð
3
øð	
úò #bð
øð1Eø÷ E÷ Eñ Eüs«   ‚'F©EªF­$E0ÁEÁ,E0Á>E!Á?.E0Â-E#Â.E0ÃE%ÃE0ÃE'Ã0AE0Ä2E,Ä3E0ÅFÅE.Å
FÅE0Å!E0Å#E0Å%E0Å'E0Å.FÅ0FÅ6E9Å7FÅ>Fc                 óÀ   — t        j                  «       }|€y	 |j                  | «       y# t        $ r)}t	        j
                  dt        |«      «       Y d}~yd}~ww xY w)zËUpdate the Prometheus team members gauge after a membership change.

    No-ops when the Prometheus callback is not registered, and never lets a
    metric failure break the team add/delete request.
    Nz2Prometheus: failed to emit team members metric: %s)r   Úget_instanceÚset_team_members_metricrC  r   r†  r¡   )rÐ  Úprometheus_loggerrv  s      r�   Ú_emit_team_members_metricr  ç
  s]   € ô  0×<Ñ<Ó>ÐØÐ ØðaØ×1Ñ1°$Õ7øÜò aÜ×"Ñ"Ð#WÔY\Ð]^ÓY_×`Ñ`ûðaús   ™+ «	A´AÁArƒ  c              ƒ   óè   K  — t        d„ | D «       «      }|s
t        «       S t        t        |«      «      j                  ddt	        |«      ii¬«      ƒ d{  –—† }t        d„ |xs dD «       «      S 7 Œ­w)zÎReturn the caller-supplied user_ids that already have a user row.

    Resolved with a single query so the number of members in the request does
    not translate into that many concurrent connections.
    c              3   óN   K  — | ]  }|j                   €Œ|j                   –— Œ y ­wr¥   r   ©rØ  r!  s     r�   rÙ  z4_resolve_existing_member_user_ids.<locals>.<genexpr>ÿ
  s    è ø€ Ò)m¸VÐRX×R`ÑR`ÑRl¨&¯.­.Ñ)mùrÛ  r¯   r³  r�  Nc              3   óN   K  — | ]  }|j                   €Œ|j                   –— Œ y ­wr¥   r   ©rØ  rÎ  s     r�   rÙ  z4_resolve_existing_member_user_ids.<locals>.<genexpr>
  s   è ø€ ÒV d¸T¿\¹\Ñ=U�T—\•\ÑVùrÛ  r›   )rŸ  rµ   r   r“  Úsorted)rƒ  r$  Úrequested_user_idsÚfounds       r�   Ú!_resolve_existing_member_user_idsr  ö
  s}   è ø€ ô !*Ñ)mÀwÔ)mÓ mÐÙÜ‹{Ðä)¬.¸Ó*GÓH×RÑRàØ”fÐ/Ó0ðð
ð Só ÷ €Eô ÑV¨eªk°rÔVÓVÐVðús   ‚AA2ÁA0ÁA2Úcaller_supplied_user_idsrš  c                 ó6   ‡— t        ˆfd„| D «       «      }||z  S )a|  Return the user_ids that already had a user row before this request.

    Combines the caller-supplied ids that resolved to a user with the ids
    ``_validate_and_populate_member_user_info`` filled in, which it only does
    from a matched user row. Deriving it that way keeps this in step with the
    email matching that resolution performs, rather than repeating it here.
    c              3   ój   •K  — | ]*  }|j                   �|j                   ‰vr|j                   –— Œ, y ­wr¥   r   )rØ  r!  r  s     €r�   rÙ  z)_pre_existing_user_ids.<locals>.<genexpr>  s3   øè ø€ ò *àØ�>‰>Ð%¨&¯.©.Ð@XÑ*Xð 	��ñ*ùs   ƒ03)rŸ  )rƒ  r  rš  Úpopulated_user_idss    `  r�   Ú_pre_existing_user_idsr    s+   ø€ ô !*ó *àô*ó !Ðð
 Ð1Ñ1Ð1rœ   é
   Ú_MAX_REPORTED_UNKNOWN_USER_IDSc           
      óH  ‡— |j                   t        j                  t        j                  j                  fv ryt	        ˆfd„| D «       «      }|sydj                  |dt         «      }t        |«      t        z
  }t        dddj                  ||dkD  rd|› d	�nd
«      i¬«      ‚)zöRestrict adding a caller-chosen user_id that has no user row yet to proxy admins.

    Team and org admins keep the ability to add users that already exist and to
    invite new ones by user_email, where the user_id is allocated server-side.
    Nc              3   ón   •K  — | ],  }|j                   €Œ|j                   ‰vsŒ|j                   –— Œ. y ­wr¥   r   )rØ  r!  rš  s     €r�   rÙ  z8_validate_member_user_id_provisioning.<locals>.<genexpr>4  s/   øè ø€ ò $Ø!°·±Ñ0JÈvÏ~É~ÐevÒOvˆ��ñ$ùs   ƒ5•5¤5z, rö  r  z¤Only proxy admins can add a user_id that does not exist yet: {}{}. Add the member by user_email to invite a new user, or ask a proxy admin to create the user first.r   z and z morerA  rS  )
rV  r0   rW  r¢   rò  Újoinr  r–  r   rÏ  )rƒ  rš  rî   Úunknown_user_idsÚlistedÚ	remainings    `    r�   Ú%_validate_member_user_id_provisioningr  $  s¼   ø€ ð ×"Ñ"Ü×$Ñ$Ü×$Ñ$×*Ñ*ð'ñ ð 	ä#ó $Ø%,ô$ó Ðñ Øà—I‘IÐ.Ð/NÔ0NÐOÓP€FÜÐ+Ó,Ô/MÑM€IÜ
Øàð,ç,2©F°6ÐW`ÐcdÒWd¸UÀ9À+ÈUÑ;SÐjlÓ,mð	
ô	ð 	rœ   c                 ó<   — t        dt        d„ | D «       «      i«      S )zÄSerialize a team's member list for an audit-log value.

    The audit-log columns hold a JSON object, so the member list is nested
    under a key rather than serialized as a top-level array.
    rÙ   c              3   ó<   K  — | ]  }|j                  «       –— Œ y ­wr¥   )r¹   r  s     r�   rÙ  z'_members_audit_value.<locals>.<genexpr>P  s   è ø€ Ò'RÀ¨×(9Ñ(9×(;Ñ'Rùs   ‚)r   rò  )rƒ  s    r�   Ú_members_audit_valuer  H  s&   € ô à ¤%Ñ'RÈ'Ô'RÓ"Rð	
óð rœ   Úbefore_membersÚafter_membersc              ƒ   óð   ‡‡‡‡	K  — ddl mŠ	 t        ˆ	ˆˆˆfd„|D «       «      } ‰	| dd‰‰t        j                  t        |«      t        |«      ¬«      }t        j                  g |¢|‘­Ž ƒ d{  –—†  y7 Œ­w)zÉRecord the membership change, and any user row it created, in the audit log.

    The entries are written concurrently so a request adding many members does
    not pay for them one after another.
    r   )Úcreate_object_audit_logc              3   óÔ   •K  — | ]_  }|j                   �Q|j                   ‰vrC ‰|j                   dd ‰‰t        j                  d t        |j	                  d¬«      «      ¬«      –— Œa y ­w)Nr?  TrÑ   ©rE  rF  r  rî   r
  r  rH  Úafter_value)r¯   r/   ÚUSER_TABLE_NAMEr   r¹   )rØ  rÎ  r   rš  r
  rî   s     €€€€r�   rÙ  z5_create_team_member_add_audit_logs.<locals>.<genexpr>e  sm   øè ø€ ò (ð Ø�<‰<Ð#¨¯©Ð<MÑ(Mñ 	 Ø—l‘lØØ#Ø/Ø%=Ü(×8Ñ8ØÜ" 4§?¡?À ?Ó#EÓF÷		
ð 		
ñ(ùs   ƒA%A(rœ  Nr"  )rK  r   rò  r/   rb  r  r]  Úgather)
r•   rÙ  rš  r  r  rî   r
  Úcreated_user_entriesÚmembership_entryr   s
     `  ``  @r�   Ú"_create_team_member_add_audit_logsr(  U  sz   ûè ø€ õ Tä"'ö (ð "ô(ó #Ðñ 6ØØØØ+Ø!9Ü$×4Ñ4Ü)¨.Ó9Ü(¨Ó7ô	Ðô �.‰.Ð
AÐ.Ð
AÐ0@Ò
A×AÒAús   †A(A6Á.A4Á/A6c           	   ƒ   ó„  K  — | j                   €| j                  €t        dddi¬«      ‚| j                   �Û| j                  �Ï|j                  d| j                   idd¬	«      ƒ d{  –—† }|�t	        |t
        «      rt        |«      d
k(  r| S t	        |t
        «      r+t        |«      dkD  rt        ddd| j                   › d�i¬«      ‚|d
   }|j                  | j                  k7  r*t        ddd| j                   › d| j                  › d�i¬«      ‚| S | j                   �º| j                  €®t        |«      j                  d| j                   ddœi¬«      ƒ d{  –—† }|€| S |j                  d| j                   idd¬	«      ƒ d{  –—† }|r;t	        |t
        «      r+t        |«      dkD  rt        ddd| j                   › d�i¬«      ‚|j                  | _        | S | j                  �R| j                   €Ft        |«      j                  d| j                  i¬«      ƒ d{  –—† }|€| S |j                   | _         | S | S 7 �ŒÒ7 Œã7 Œ¹7 Œ$­w)aŽ  
    Validate and populate user_email/user_id for a member.

    Logic:
    1. If both user_email and user_id are provided, verify they belong to the same user (use user_email as source of truth)
    2. If only user_email is provided, populate user_id from DB
    3. If only user_id is provided, populate user_email from DB (if user exists)
    4. If only user_id is provided and doesn't exist, allow it to pass with user_email as None (will be upserted later)
    5. If user_email and user_id mismatch, throw error

    Returns a Member with user_email and user_id populated (user_email may be None if only user_id provided and user doesn't exist).
    NrÅ  r  z-Either user_id or user_email must be providedrS  r¾  rÎ  Úfind_all)Úkey_valr  r  r   rÈ  z!Multiple users found with email 'z '. Please use 'user_id' instead.zuser_email 'z' and user_id 'z!' do not belong to the same user.Úinsensitive)ÚequalsÚmoder�  r¯   )
r¾  r¯   r   rQ  r_  r§  r–  r/  Ú
find_firstr  )r!  r$  Úusers_by_emailÚuser_by_emailÚ
user_by_ids        r�   Ú'_validate_and_populate_member_user_infor3  ‚  s   è ø€ ð  ×ÑÐ  V§^¡^Ð%;ÜØØÐLÐMô
ð 	
ð ×ÑÐ$¨¯©Ð)Cð  -×5Ñ5Ø! 6×#4Ñ#4Ð5ØØ!ð  6ó  
÷ 
ˆð Ð!¤j°ÄÔ&FÌ3È~ÓK^ÐbcÒKcàˆMä�n¤dÔ+´°NÓ0CÀaÒ0GÜØàÐ@À×ARÑARÐ@SÐSsÐtðôð ð ' qÑ)ˆð × Ñ  F§N¡NÒ2ÜØà˜|¨F×,=Ñ,=Ð+>¸oÈfÏnÉnÐM]Ð]~Ððôð ð ˆð ×ÑÐ$¨¯©Ð)?Ü& }Ó5×@Ñ@Ø¨F×,=Ñ,=À}Ñ!UÐVð Aó 
÷ 
ˆð Ð àˆMð  -×5Ñ5Ø! 6×#4Ñ#4Ð5ØØ!ð  6ó  
÷ 
ˆñ œj¨¼Ô>Ä3À~ÓCVÐYZÒCZÜØàÐ@À×ARÑARÐ@SÐSsÐtðôð ð '×.Ñ.ˆŒØˆð ‡~�~Ð! f×&7Ñ&7Ð&?Ü"*¨=Ó"9×"EÑ"EÈYÐX^×XfÑXfÐLgÐ"EÓ"h×hˆ
àÐð ˆMð '×1Ñ1ˆÔØˆà€MðW
ùðF
øð
øð( iúsJ   ‚A#I Á%H7Á&C0I ÅH:Å+I ÆH<ÆBI ÈH>ÈI È:I È<I È>I rÍ  c           
   ƒ   ó  K  — ddl m}m}m}m}m} 	 t        || |¬«       t        | j                  «       t        t        |«      }t        | j                  ||d|dd¬«      ƒ d{  –—† }|€t        dd	d
t        | dd«      › �i¬«      ‚t        j                   |j#                  «       «      }	t%        | |	¬«       t'        ||	| ¬«      ƒ d{  –—†  t)        | j*                  t,        «      rt/        | j*                  «      n| j*                  f}
t1        d„ |
D «       «      }t3        |
|¬«      ƒ d{  –—† }t5        |
||¬«       t/        |	j6                  «      }t)        | j*                  t8        «      r t;        | j*                  |¬«      ƒ d{  –—†  n@t)        | j*                  t,        «      r&| j*                  D ]  }t;        ||¬«      ƒ d{  –—†  Œ t=        |
||¬«      }t?        | |	|||¬«      ƒ d{  –—† \  }}}tA        |	«       tC        | j                  |||t/        |	j6                  «      ||¬«      ƒ d{  –—†  tE        j                   i |j#                  «       ¥||dœ¥«      S # t        $ r}|‚d}~ww xY w7 �Œ7 �Œ±7 �ŒQ7 Œ÷7 Œº7 Œ”7 ŒP­w)aî  
    Add new members (either via user_email or user_id) to a team

    If user doesn't exist, new user row will also be added to User Table

    Only proxy_admin or admin of team, allowed to access this endpoint.
    ```

    curl -X POST 'http://0.0.0.0:4000/team/member_add'     -H 'Authorization: Bearer sk-1234'     -H 'Content-Type: application/json'     -d '{"team_id": "45e3e396-ee08-4a61-a88e-16b3ce7e0849", "member": {"role": "user", "user_id": "krrish247652@berri.ai"}}'

    ```
    r   )r
  rµ  r$  rJ  rI  )r$  rl  rµ  NFT©r•   r$  rI  Úparent_otel_spanrJ  Úcheck_cache_onlyÚcheck_db_onlyr‹  r  zTeam not found for team_id=r•   rS  )rl  rx  )rî   r;  rl  c              3   óN   K  — | ]  }|j                   €Œ|j                   –— Œ y ­wr¥   r   r  s     r�   rÙ  z"team_member_add.<locals>.<genexpr>7  s    è ø€ Ò(v¸FÐ[a×[iÑ[iÑ[u¨¯­Ñ(vùrÛ  )rƒ  r$  )rƒ  rš  rî   )r!  r$  )rƒ  r  rš  r:  )r•   rÙ  rš  r  r  rî   r
  )rÙ  rÚ  )#rL  r
  rµ  r$  rJ  rI  r»  r   rb   rÊ   r   rs   rP   r•   r¦  r,   rM  r¹   rÊ  rÔ  r_  r!  r§  rò  rŸ  r  r  rÙ   r1   r3  r  r\  r  r(  r<   )rl  rî   r
  rµ  r$  rJ  rI  rv  rx  r;  rô  r  rš  Úmembers_before_addr™  Úpre_existing_user_idsrý  rÙ  rÚ  s                      r�   Úteam_member_addr<  ê  sÂ  è ø€ ÷4õ ðÜ#Ø'ØØ%õ	
ô ˜T×1Ñ1Ô2äœ }Ó5€Mä%4Ø—‘Ø#Ø-ØØ+ØØô&÷  Ðð Ð ÜØØÐ:¼7À4ÈÐTXÓ;YÐ:ZÐ[Ð\ô
ð 	
ô
 !2× @Ñ @ÐAR×A]ÑA]ÓA_Ó `Ðä%ØØ,õô 0Ø+Ø-Øô÷ ð ô 6@ÀÇÁÌTÔ5Rœu T§[¡[Ô1ÐY]×YdÑYdÐXfÐÜ(Ñ(vÐFWÔ(vÓvÐÜ%FØ!Ø#ô&÷  Ðô *Ø!Ø+Ø+õô
 !&Ð&8×&KÑ&KÓ LÐô �$—+‘+œvÔ&Ü5Ø—;‘;Ø'ô
÷ 	
ñ 	
ô 
�D—K‘K¤Ô	&Ø—‘ò 	ˆAÜ9ØØ+ô÷ ñ ð	ô $:Ø!Ø!9Ø+ô$Ðô (ØØ-Ø#Ø+Ø!9ô÷ 	ñ	ØØØ ô Ð0Ô1ä
,Ø—‘Ø#Ø/Ø)ÜÐ.×AÑAÓBØ+Ø!9ô÷ ð ô !×/Ñ/ð	
Ø×%Ñ%Ó'ð	
à*Ø(@ò	
óð øôy ò Øˆûðúð ùð.ùð ùð	
øðøð	øðús¤   ‚J’I$  AJÁ$I7Á%A$JÃ	I:Ã
A"JÄ,I=Ä-AJÆJ Æ	>JÇJÇ'JÇ/JÇ0AJÈ5JÈ6.JÉ$	I4É-I/É/I4É4JÉ:JÉ=JÊ JÊJÊJÊJc                 óê   — |j                   d uxr) | j                   d uxr |j                   | j                   k(  xs9 |j                  d uxr) | j                  d uxr |j                  | j                  k(  S r¥   rä  )r!  rl  s     r�   Ú_is_member_addressed_byr>  w  sl   € Ø�L‰L Ð$Òf¨¯©¸tÐ)CÒfÈÏÉÐX^×XfÑXfÑHfò Ø�‰˜tÐ#Òn¨×(9Ñ(9ÀÐ(EÒnÈ$Ï/É/Ð]c×]nÑ]nÑJnðrœ   .c                 óž   ‡— t        ˆfd„| j                  D «       «      }| j                  D �cg c]  }t        |‰«      rŒ|‘Œ }}||fS c c}w )a_  Split a team's members_with_roles into the entries the request addresses and the ones that stay.

    The addressed entries are returned rather than a bare found/not-found flag because they carry the
    user_id the request may not have supplied, and every cleanup that keys off the user rather than
    off the roster has to run against that id.
    c              3   ó<   •K  — | ]  }t        |‰«      sŒ|–— Œ y ­wr¥   )r>  )rØ  r™  rl  s     €r�   rÙ  z._cleanup_members_with_roles.<locals>.<genexpr>‡  s"   øè ø€ ò (ØÔ;RÐSTÐVZÕ;[Œñ(ùrñ  )rò  rÙ   r>  )rx  rl  Úremoved_team_membersr™  Únew_team_memberss    `   r�   Ú_cleanup_members_with_rolesrC  }  s]   ø€ ô #(ó (Ø$×7Ñ7ô(ó #Ðð +<×*NÑ*NÖw QÔVmÐnoÐquÕVvšqÐwÐÐwØÐ!1Ð1Ð1ùò xs   ®A
Á A
ú/team/member_deletec              ƒ   óR	  K  — ddl m} |€t        dddi¬«      ‚| j                  €t        ddd	i¬«      ‚| j                  €| j
                  €t        ddd
i¬«      ‚t        |«      j                  d| j                  i¬«      ƒ d{  –—† }|€t        ddd| j                  › d�i¬«      ‚t        j                  |j                  «       «      }|j                  t        j                  j                  k7  rKt        ||¬«      s>t!        ||¬«      ƒ d{  –—† s)t        dddj#                  d|j                  «      i¬«      ‚|j%                  «       4 ƒd{  –—† }|j'                  t(        | j                  «      ƒ d{  –—†  t+        |«      j-                  || j                  «      ƒ d{  –—† }|€t        ddd| j                  › d�i¬«      ‚t/        t        | j                  |¬«      | ¬«      \  }}|st        dddi¬«      ‚||_        |D �	cg c]  }	|	j                  «       ‘Œ }
}	t3        d„ |D «       «      }|rddt5        |«      iind| j
                  i}|}|j6                  j9                  |¬«      ƒ d{  –—† }|j;                  | j                  �| j                  fndd„ |D «       «      }|j<                  j9                  dt5        |«      i| j                  dœ¬«      ƒ d{  –—† }t?        |«      jA                  d| j                  idtC        jD                  |
«      i¬«      ƒ d{  –—†  |D ]x  }| j                  |jF                  v sŒ|j6                  jA                  d|j                  idd |jF                  D �cg c]  }|| j                  k7  sŒ|‘Œ c}ii¬«      ƒ d{  –—†  Œz t5        |«      D ]3  }|jH                  jK                  | j                  |d!œ¬«      ƒ d{  –—†  Œ5 |rY|rdd"l&m'}  ||||d|¬#«      ƒ d{  –—†  |j<                  jK                  dt5        |«      i| j                  dœ¬«      ƒ d{  –—†  ddd«      ƒd{  –—†  tQ        |«       |S 7 �Œà7 �ŒX7 �Œ7 �Œô7 �ŒÊc c}	w 7 �Œ7 �Œ—7 �ŒUc c}w 7 Œá7 Œ¢7 Œƒ7 ŒI7 Œ;# 1 ƒd{  –—†7  sw Y   ŒKxY w­w)$až  
    [BETA]

    delete members (either via user_email or user_id) from a team

    If user doesn't exist, an exception will be raised
    ```
    curl -X POST 'http://0.0.0.0:8000/team/member_delete' 
    -H 'Authorization: Bearer sk-1234' 
    -H 'Content-Type: application/json' 
    -d '{
        "team_id": "45e3e396-ee08-4a61-a88e-16b3ce7e0849",
        "user_id": "krrish247652@berri.ai"
    }'
    ```
    r   r&  Nr  r  r  rS  rÅ  r–  ú2Either user_id or user_email needs to be passed inr•   r�  úTeam id=ú does not exist in dbrR  rö  rÌ  rD  )r•   rÙ   )rx  rl  zUser not found in teamc              3   óN   K  — | ]  }|j                   €Œ|j                   –— Œ y ­wr¥   r   ©rØ  r™  s     r�   rÙ  z%team_member_delete.<locals>.<genexpr>ó  s    è ø€ Ò+m¸!ÐWX×W`ÑW`ÑWl¨A¯I­IÑ+mùrÛ  r¯   r³  r¾  r›   c              3   óN   K  — | ]  }|j                   sŒ|j                   –— Œ y ­wr¥   r   r  s     r�   rÙ  z%team_member_delete.<locals>.<genexpr>ý  s   è ø€ ÒI˜d¸D¿L»LˆT�\�\ÑIùrÛ  ©r¯   r•   rÙ   r’  r¼  r¡  )r•   r¯   ©Ú$_persist_deleted_verification_tokens)Úkeysr$  rî   r  r)  ))rL  r$  r   r•   r¯   r¾  r'  r  r,   rM  r¹   rV  r0   rW  r¢   r\   r[   rÏ  r)  rø  re   r~   rù  rC  rÙ   rŸ  r  r  r“  Úunionr  r+  r  rÔ   rT  r¼  r  Údelete_manyÚ;litellm.proxy.management_endpoints.key_management_endpointsrN  r  )rl  rî   r$  Ú_existing_team_rowrx  r)  Úfresh_membersrA  rB  r™  Ú_db_new_team_membersÚremoved_user_idsr+  Ú	member_txÚexisting_user_rowsÚuser_ids_to_deleteÚkeys_to_deleteÚexisting_userrÐ  Ú_uidrN  s                        r�   Úteam_member_deleter]  Ž  sÿ  è ø€ õ: 9àÐÜ¨°WÐ>OÐ4PÔQÐQà‡|�|ÐÜ¨°WÐ>TÐ4UÔVÐVà‡|�|Ð §¡Ð 7ÜØØÐQÐRô
ð 	
ô
 '/¨}Ó&=×&IÑ&IÐQZÐ\`×\hÑ\hÐPiÐ&IÓ&j× jÐàÐ!ÜØØ˜x¨¯© ~Ð5JÐKÐLô
ð 	
ô  1×?Ñ?Ð@R×@]Ñ@]Ó@_Ó`Ðð
 	×#Ñ#Ô'7×'CÑ'C×'IÑ'IÒIÜ#Ð6GÐRcÕdÜ1ÐDUÐ`qÔr×rÐräØàÐe×lÑlØ)Ð+<×+DÑ+Dóðô
ð 	
ð$ ×ÑÓ!÷ Qð Q RØ�l‰lÔ1°4·<±<Ó@×@Ð@ä%3°MÓ%B×%`Ñ%`ÐacÐei×eqÑeqÓ%r×rˆØÐ ÜØØ 8¨D¯L©L¨>Ð9NÐ!OÐPôð ô
 2MÜ/¸¿¹ÐYfÔgØô2
Ñ.ÐÐ.ñ
 $Ü¨C¸ÐBZÐ8[Ô\Ð\à/?ÐÔ,àK[Ö2\Àa°1·<±<µ>Ð2\ÐÐ2\ô #,Ñ+mÐ?SÔ+mÓ"mÐá=MˆY˜œvÐ&6Ó7Ð8Ñ9ÐT`Ðbf×bqÑbqÐSrð 	ð -/ˆ	Ø*3×*EÑ*E×*OÑ*OÐV]Ð*OÓ*^×$^Ðð %5×$:Ñ$:Ø#Ÿ|™|Ð7ˆT�\‰\‰O¸RÙIÐ&8ÔIó%
Ðð '0×&IÑ&I×&SÑ&Sà ¤&Ð);Ó"<Ð=ØŸ<™<ñð 'Tó '
÷ !
ˆô ˜"‹o×$Ñ$Ø˜dŸl™lÐ+Ø&¬¯
©
Ð3GÓ(HÐIð %ó 
÷ 	
ð 	
ð
 0ò 	ˆMØ�|‰|˜}×2Ñ2Ò2Ø×*Ñ*×1Ñ1Ø$ m×&;Ñ&;Ð<Ø! E¸]×=PÑ=PÖ+i°TÐTXÐ\`×\hÑ\hÓThªDÒ+iÐ#jÐkð 2ó ÷ ñ ð	ô Ð-Ó.ò 	jˆDØ×+Ñ+×7Ñ7È$Ï,É,ÐcgÑ>hÐ7Ói×iÑið	jñ Ùõñ ;Ø'Ø"/Ø&7Ø'+Øô÷ ð ð ×.Ñ.×:Ñ:à $¤fÐ-?Ó&@ÐAØ#Ÿ|™|ñð ;ó ÷ ð ÷YQ÷ Qôf Ð/Ô0àÐðo !kùð sùð(QùØ@ùàrûò" 3]ð %_ùð!
ùð	
ûò ,jðøð jøðøðøðYQø÷ Q÷ Qñ Qüs9  ‚BR'ÂQ&ÂB
R'ÄQ)ÄAR'ÅQ,ÅR'Å$RÅ;Q/Å<,RÆ(Q2Æ)A$RÈQ5È$ARÉ8Q:É9A-RË&Q=Ë'ARÌ+R Ì,!RÍ2RÎ RÎRÎRÎ&RÎ'A RÏ'R
Ï( RÐRÐ	;RÑRÑRÑ	R'ÑRÑR'Ñ)R'Ñ,R'Ñ/RÑ2RÑ5RÑ=RÒ RÒRÒ
RÒRÒRÒR'ÒR$ÒRÒR$Ò R'rÝ   rz  ry  rÊ   rÑ  )rÐ  rz  ry  rÊ   rÑ  Ú_MEMBER_BUDGET_PATCH_FIELDSc                 ó�   — | j                  d¬«      }t        j                  «       D ��ci c]  \  }}||v r|||   “Œ c}}S c c}}w )zµMap the budget fields the request actually set (merge-patch: a sent
    value updates, an explicit null clears, an absent field is left untouched)
    to their budget-table columns.Tr˜  )r¹   r^  rÍ  )rl  ÚprovidedÚrequest_fieldÚcolumns       r�   Ú_build_member_budget_patchrc  <  sV   € ð —o‘o°D�oÓ9€Hô &A×%FÑ%FÓ%H÷á!ˆM˜6Ø˜HÑ$ð 	�˜Ñ'Ñ'óð ùó s   ªAz/team/member_updatec           
   ƒ   óø  K  — ddl m}m}m} |€t	        dddi¬«      ‚| j
                  €t	        ddd	i¬«      ‚| j                  d
k(  r|st	        dd¬«      ‚| j                  €| j                  €t	        dddi¬«      ‚t        | j                  «       t        |«      j                  d| j
                  i¬«      ƒ d{  –—† }|€t	        ddd| j
                  › d�i¬«      ‚t        j                  |j                  «       «      }|j                   t"        j$                  j&                  k7  rKt)        ||¬«      s>t+        ||¬«      ƒ d{  –—† s)t	        dddj-                  d|j
                  «      i¬«      ‚t/        || j
                  d|¬«      ƒ d{  –—† }|d   }	d}
| j                  �| j                  }
nT| j                  �H|d   j0                  D ]6  }|j                  €Œ|j                  | j                  k(  sŒ*|j                  }
 n |
€t	        ddd| › �i¬«      ‚d}|d   D ]  }|j                  |
k(  sŒ|j2                  } n d}|	j4                  �-|	j4                  j7                  d«      }t9        |t:        «      r|}t=        | «      }|j?                  «       4 ƒd{  –—† }tA        || j
                  |
||||¬«      ƒ d{  –—†  ddd«      ƒd{  –—†  |r tC        |
| j
                  |¬«      ƒ d{  –—†  | j                  �æg }|	j0                  D ]l  }|j                  |
k(  rJ|jE                  tG        |j                  | j                  | j                  xs |j                  ¬«      «       Œ\|jE                  |«       Œn ||	_        |D �cg c]  }|j                  «       ‘Œ }}t        |«      jI                  d| j
                  idtK        jL                  |«      i¬«      ƒ d{  –—†  tO        | j
                  |
| j                  | jP                  | jR                  | jT                  | j                  | jV                  ¬«      S 7 �Œ‹7 �Œ7 �Œ¼7 �Œ¯7 �ŒŽ7 �Œ�# 1 ƒd{  –—†7  sw Y   �Œ’xY w7 �Œxc c}w 7 Œ�­w) zE
    [BETA]

    Update team member budgets and team member role
    r   )rµ  r$  rI  Nr  r  r  rS  rÅ  r–  r"  a
  Assigning team admins is a premium feature. You must be a LiteLLM Enterprise user to use this feature. If you have a license please set `LITELLM_LICENSE` in your env. Get a 7 day trial key here: https://www.litellm.ai/#trial. Pricing: https://www.litellm.ai/#pricingrF  r•   r�  rG  rH  rR  rö  rÌ  rD  )r  r•   Ú	key_limitrî   Ú	team_infoz*User id doesn't exist in team table. Data=r¸  r]  )r)  r•   r¯   Úexisting_budget_idrî   Úbudget_patchÚteam_default_budget_id)r¯   r•   rI  )r¯   r#  r¾  rÙ   r’  )r•   r¯   r¾  rÐ  rz  ry  rÊ   rÑ  ),rL  rµ  r$  rI  r   r•   r#  r¯   r¾  rb   rÊ   r'  r  r,   rM  r¹   rV  r0   rW  r¢   r\   r[   rÏ  rf  rÙ   rê   rÎ   r{  r_  r¡   rc  r)  r`   rR   r”  r1   r  rÔ   rT  rC   rÐ  rz  ry  rÑ  )rl  r  rî   rµ  r$  rI  rS  rx  Úreturned_team_inforL  Úreceived_user_idr!  Úidentified_budget_idrº  ri  Úraw_default_budget_idrh  r)  r’  r™  rü  s                        r�   Úteam_member_updatern  H  s¦  è ø€ ÷" [ÑZàÐÜ¨°WÐ>OÐ4PÔQÐQà‡|�|ÐÜ¨°WÐ>TÐ4UÔVÐVà‡y�y�GÒ¡LäØð `ô
ð 	
ð ‡|�|Ð §¡Ð 7ÜØØÐQÐRô
ð 	
ô
 ˜T×1Ñ1Ô2ä&.¨}Ó&=×&IÑ&IÐQZÐ\`×\hÑ\hÐPiÐ&IÓ&j× jÐàÐ!ÜØØ˜x¨¯© ~Ð5JÐKÐLô
ð 	
ô  1×?Ñ?Ð@R×@]Ñ@]Ó@_Ó`Ðð
 	×#Ñ#Ô'7×'CÑ'C×'IÑ'IÒIÜ#Ð6GÐRcÕdÜ1ÐDUÐ`qÔr×rÐräØàÐe×lÑlØ)Ð+<×+DÑ+Dóðô
ð 	
ô ?HØ!Ø—‘ØØ+ô	?÷ 9Ðð +¨;Ñ7€Jð $(ÐØ‡|�|ÐØŸ<™<ÑØ	�‰Ð	$Ø(¨Ñ5×HÑHò 	ˆFØ× Ñ Ñ,°×1BÑ1BÀdÇoÁoÓ1UØ#)§>¡>Ð Ùð	ð
 ÐÜØØÐIÈ$ÈÐPÐQô
ð 	
ð
 (,ÐØ Ð!3Ñ4ò ˆØ�:‰:Ð)Ó)Ø#%§<¡<Ð Ùðð *.ÐØ×ÑÐ&Ø'1×':Ñ':×'>Ñ'>Ð?VÓ'WÐÜÐ+¬SÔ1Ø%:Ð"ô 5°TÓ:€LØ×ÑÓ!÷ 	
ð 	
 RÜ+ØØ—L‘LØ$Ø3Ø/Ø%Ø#9ô
÷ 	
ð 	
÷	
÷ 	
ñ Ü0Ø$Ø—L‘LØ1ô
÷ 	
ð 	
ð ‡y�yÐØ,.ˆØ ×3Ñ3ò 
	,ˆFØ�~‰~Ð!1Ò1Ø×#Ñ#ÜØ &§¡Ø!ŸY™YØ#'§?¡?Ò#G°f×6GÑ6Gôõð ×#Ñ# FÕ+ð
	,ð )5ˆ
Ô%àGSÖ.TÀ!¨q¯|©|­~Ð.TÐÐ.TÜ�}Ó%×,Ñ,Ø˜dŸl™lÐ+Ø&¬¯
©
Ð3CÓ(DÐEð -ó 
÷ 	
ð 	
ô
 $Ø—‘Ø Ø—?‘?Ø×2Ñ2Ø—.‘.Ø—.‘.Ø×,Ñ,Ø×*Ñ*ô	ð 	ðW !kùð sùð9ùðT	
ùð	
ùð	
ù÷ 	
÷ 	
ò 	
úð	
ûò. /Uð	
úsÓ   ‚B;Q:Â=QÂ>B
Q:ÅQÅ	A	Q:ÆQÆAQ:Ç"Q:Ç<<Q:È9A)Q:Ê"QÊ#Q:Ê& QËQËQËQ:ËQË!Q:Ë8Q0Ë9BQ:ÎQ3Î(AQ:Ï*Q8Ï+AQ:ÑQ:ÑQ:ÑQ:ÑQÑQ:ÑQ-Ñ Q#Ñ!Q-Ñ(	Q:Ñ3Q:c                 ó”   — | |j                   k(  r9|j                  t        j                  k7  rt	        t
        j                  d«       yyy)aÃ  
    _verify_team_access authorizes a team admin (or org admin) over their own
    team, with no check that the target user_id differs from the caller. Left
    unchecked, that admin could target their own LiteLLM_TeamMembership row and
    repeatedly reset it to 0 right before it crosses their per-member cap,
    consuming the shared team budget without the configured limit ever binding.
    Only a proxy admin may reset an admin's own spend.
    z/Cannot reset your own spend. Ask a proxy admin.N)r¯   rV  r0   rW  Ú_raise_reset_spend_errorr   rX  ©r¯   rî   s     r�   Ú_check_not_resetting_own_spendrr  æ  sB   € ð Ð#×+Ñ+Ò+Ð0A×0KÑ0KÔO_×OkÑOkÒ0kÜ ¤×!:Ñ!:Ð<mÕnð 1lÐ+rœ   rT  rÄ  c                 ó$   — d|i}t        | |¬«      ‚)Nr  rS  ©r   )rT  rÄ  rU  s      r�   rp  rp  ó  s   € Ø˜gÐ&€FÜ
 K¸Ô
?Ð?rœ   Úreset_toÚ
membershipc                 óè  — t        | t        t        f«      st        t        j
                  d«       t        | «      }t        j                  |«      r|dk  rt        t        j
                  d«       |j                  xs d}||kD  r!t        t        j
                  d|› d|› d�«       |j                  r|j                  j                  nd }|�&||kD  r!t        t        j
                  d|› d|› d�«       |S )	Nzreset_to must be a floatr   z%reset_to must be a finite number >= 0ç        z
reset_to (z) must be <= current spend (r  z) must be <= budget ()r_  r™   rã   rp  r   ÚHTTP_400_BAD_REQUESTrM  rN  Úspendr´  rÝ   )ru  rv  Úreset_to_floatÚcurrent_spendrÝ   s        r�   Ú'_validate_team_member_reset_spend_valuer}  ø  sè   € ô �h¤¤e Ô-Ü ¤×!<Ñ!<Ð>XÔYä! (›O€NÜ�=‰=˜Ô(¨N¸QÒ,>Ü ¤×!<Ñ!<Ð>eÔfà%×+Ñ+Ò2¨s€MØ˜Ò%Ü Ü×'Ñ'Ø˜Ð(Ð(DÀ]ÀOÐSTÐUô	
ð
 GQ×FeÒFe˜
×7Ñ7×BÒBÐko€JØÐ .°:Ò"=Ü Ü×'Ñ'Ø˜Ð(Ð(=¸j¸\ÈÐKô	
ð
 Ðrœ   z,/team/{team_id}/member/{user_id}/reset_spendc              ƒ   óè  K  — ddl m}m}m} |€t	        t
        j                  d«       t        | ||d|d¬«      ƒ d{  –—† }t        ||¬«      ƒ d{  –—†  t        ||¬«       d	|| d
œi}t        |«      j                  |ddi¬«      ƒ d{  –—† }	|	€!t	        t
        j                  d|› d| › d�«       t        j                  |	j                  «       «      }
|
j                   xs d}t#        |j$                  |
«      }t        |«      j'                  |d|i¬«      ƒ d{  –—†  t)        || ||¬«      ƒ d{  –—†  | ||||
j*                  r|
j*                  j,                  dœS ddœS 7 �Œ)7 �Œ7 Œß7 ŒO7 Œ:­w)aú  
    Reset a team member's tracked spend against their per-member budget.

    A member's spend is tracked separately from both their own personal
    budget and the team's own budget (LiteLLM_TeamMembership.spend), so
    neither /user/update nor /team/update can clear it: this is the only
    endpoint that does. The cross-pod spend counter and cached membership
    reads are invalidated so the reset takes effect on the member's next
    request rather than waiting on the membership cache's TTL.
    r   ©r$  rJ  rI  Nz'DB not connected. prisma_client is NoneT)r•   r$  rI  r6  rJ  r8  rY  rq  Úuser_id_team_idrL  r´  rµ  zUser z is not a member of team r÷  rx  rz  r’  )r¯   r•   rI  Ú	new_spend)r•   r¯   rz  Úprevious_spendrÝ   )rL  r$  rJ  rI  rp  r   ÚHTTP_500_INTERNAL_SERVER_ERRORrP   rZ  rr  r-  r  ÚHTTP_404_NOT_FOUNDr+   rM  r¹   rz  r}  ru  r  rR   r´  rÝ   )r•   r¯   rl  rî   r$  rJ  rI  rP  Úmembership_whereÚ_membership_rowrv  r|  ru  s                r�   Úreset_team_member_spend_fnr‡    s¶  è ø€ ÷, `Ñ_àÐÜ ¤×!FÑ!FÐHqÔrä+ØØ#Ø-ØØ+Øô÷ €Hô  xÐCTÔ
U×UÐUÜ"¨7ÐFWÕXð 	 w¸7ÑCðÐô $7°}Ó#E×#QÑ#QØØ'¨Ð.ð $Ró $÷ €Oð ÐÜ ¤×!:Ñ!:¸eÀGÀ9ÐLeÐfmÐenÐnoÐ<pÔqÜ.×=Ñ=¸o×>XÑ>XÓ>ZÓ[€Jà%×+Ñ+Ò2¨s€MÜ=¸d¿m¹mÈZÓX€Hä
˜mÓ
,×
3Ñ
3ØØ�xÐ ð 4ó ÷ ð ô
 -ØØØ-Øô	÷ ð ð ØØØ'ØDN×DcÒDc�j×5Ñ5×@Ñ@ñð ð
 jnñð ðKùð Vùðøðøð
úsX   ‚;E2½E&¾E2ÁE)Á9E2ÂE,ÂBE2ÄE.ÄE2Ä5E0Ä61E2Å)E2Å,E2Å.E2Å0E2Úresponsec           
      óô  — g }| D ]ð  }d}|j                   D ]_  }|j                  r|j                  |j                  k(  s'|j                  sŒ5|j                  |j                  k(  sŒO|j                  «       } n d}|j                  D ]:  }|j                  sŒ|j                  |j                  k(  sŒ*|j                  «       } n |j                  t        |j                  |j                  d||¬«      «       Œò |S )zS
    Convert TeamAddMemberResponse into individual TeamMemberAddResult objects
    NT)r¯   r¾  ÚsuccessrÝ  Úupdated_team_membership)rÙ  r¯   r¾  r¹   rÚ  r”  r‹   )rƒ  rˆ  Úresultsr!  rÝ  rÎ  r‹  rº  s           r�   Ú_create_results_from_responser�  ]  sé   € ð 13€Gàò 
ˆàˆØ×*Ñ*ò 	ˆDØ—’ 4§<¡<°6·>±>Ò#AØ×!Ó! d§o¡o¸×9JÑ9JÓ&Jà#Ÿ™Ó0�Ùð	ð #'ÐØ×3Ñ3ò 	ˆBØ�~‹~ "§*¡*°·±Ó">Ø*,¯-©-«/Ð'Ùð	ð
 	�‰ÜØŸ™Ø!×,Ñ,ØØ)Ø(?ôõ	
ð#
ð6 €Nrœ   z/team/bulk_member_addc           
   ƒ   óì  K  — ddl m} ddlm} |€#t	        dd|j
                  j                  i¬«      ‚| j                  r�|j                  t        j                  j                  k7  rt	        ddd	i¬«      ‚t        |«      j                  d
di¬«      ƒ d{  –—† }|D �cg c]$  }t        |j                  |j                  d¬«      ‘Œ& c}| _        | j                   st	        dddi¬«      ‚d}t#        | j                   «      |kD  rt	        ddd|› d�i¬«      ‚	 t%        t'        | j(                  | j                   | j*                  ¬«      |¬«      ƒ d{  –—† }t-        | j                   |«      }t/        | j(                  |t#        | j                   «      t#        |«      d|j1                  «       ¬«      S 7 �Œc c}w 7 Œg# t2        $ r«}	t5        j6                  |	«       t9        |	«      }
| j                   D �cg c]%  }t;        |j                  |j                  d|
¬«      ‘Œ' nc c}w }}t/        | j(                  |t#        | j                   «      dt#        | j                   «      d¬«      cY d}	~	S d}	~	ww xY w­w)a"  
    Bulk add multiple members to a team at once.
    
    This endpoint reuses the same logic as /team/member_add but provides a bulk-friendly response format.
    
    Parameters:
    - team_id: str - The ID of the team to add members to
    - members: List[Member] - List of members to add to the team
    - all_users: Optional[bool] - Flag to add all users on Proxy to the team
    - max_budget_in_team: Optional[float] - Maximum budget allocated to each user within the team
    
    Returns:
    - results: List of individual member addition results
    - total_requested: Total number of members requested for addition
    - successful_additions: Number of successful additions  
    - failed_additions: Number of failed additions
    - updated_team: The updated team object
    
    Example request:
    ```bash
    curl --location 'http://0.0.0.0:4000/team/bulk_member_add'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "team_id": "team-1234",
        "members": [
            {
                "user_id": "user1",
                "role": "user"
            },
            {
                "user_email": "user2@example.com",
                "role": "admin"
            }
        ],
        "max_budget_in_team": 100.0
    }'
    ```
    r   )r"   r&  Nr  r  rS  rö  zb`all_users=true` is restricted to PROXY_ADMIN. Org/team admins must specify explicit member lists.Ú
created_atÚdesc)rú   rÎ  )r¯   r¾  r#  rÅ  zAt least one member is requiredzMaximum z members can be added at once)r•   r!  rÐ  ©rl  rî   )r•   rŒ  Útotal_requestedÚsuccessful_additionsÚfailed_additionsrý  F)r¯   r¾  rŠ  r  )ru  r"   rL  r$  r   r�  r¢   Ú	all_usersrV  r0   rW  r/  r“  r1   r¯   r¾  rƒ  r–  r<  r@   r•   rÐ  r�  r„   r¹   rC  r   Ú	exceptionr¡   r‹   )rl  rî   r"   r$  Úall_users_in_dbrÎ  ÚMAX_BATCH_SIZErˆ  rŒ  rv  Úerror_messager!  s               r�   Úbulk_team_member_addrš  „  sk  è ø€ õd 7Ý8àÐÜØØÐ.×EÑE×KÑKÐLô
ð 	
ð
 ‡~‚~ð
 ×&Ñ&Ô*:×*FÑ*F×*LÑ*LÒLÜØàðNðôð ô (0°Ó'>×'HÑ'HÐP\Ð^dÐOeÐ'HÓ'f×!fˆð (ö
ð ô ØŸ™ØŸ?™?Øöò
ˆŒð �<Š<ÜØØÐ>Ð?ô
ð 	
ð  €NÜ
ˆ4�<‰<Ó˜>Ò)ÜØØ˜x¨Ð'7Ð7TÐUÐVô
ð 	
ð
,
ä /Ü%ØŸ™Ø—|‘|Ø#'×#:Ñ#:ôð
 0ô!
÷ 
ˆô 0°·±¸hÓGˆä(Ø—L‘LØÜ §¡Ó-Ü!$ W£ØØ!×,Ñ,Ó.ô
ð 	
ðM "gûò
ð2
ùô* ò 
ä×&Ñ& qÔ)Ü" 1›vˆð Ÿ,™,ö
ð ô  ØŸ™Ø!×,Ñ,ØØ#ö	ñ
ùò 
ˆð 
ô )Ø—L‘LØÜ §¡Ó-Ø!"Ü  §¡Ó.Øô
õ 	
ûð
üsu   ‚BI4ÂF3ÂI4Â)F6ÃAI4Ä:F= ÅF;ÅAF= Æ2I4Æ6I4Æ;F= Æ=	I1Ç.I,Ç4*HÈAI,É&I1É'I4É,I1É1I4z/team/deletec              ƒ   óÚ  K  — ddl m}m} ddlm}m}m}m}	m}
 |€t        dddi¬«      ‚| j                  €t        d	dd
i¬«      ‚g }| j                  D ]z  }	 t        |«      j                  d|i¬«      ƒ d{  –—† }|€t        ‚	 t        j                  |j!                  «       «      }t#        ||¬«      ƒ d{  –—†  |j%                  |«       Œ| t'        ||||¬«      ƒ d{  –—†   |«       rÍ| j                  D ]¾  }|j)                  |dd¬«      ƒ d{  –—† }|€Œ"|j+                  d¬«      }t-        j.                   |t1        t3        t5        j6                  «       «      t9        j:                  t<        j>                  «       ||||¬«      |j@                  tB        jD                  |dd|¬«	      ¬«      «       ŒÀ ddl#m$} tK        |«      jM                  dd| j                  ii¬«      ƒ d{  –—† }|r |||||¬«      ƒ d{  –—†  |jO                  | j                  d¬«      ƒ d{  –—†  tQ        ||
|	¬ «      ƒ d{  –—†  dd!l)m*} dd"lm+}  || j                  ||¬#«      ƒ d{  –—†  |D ]w  }|jX                  }g }|D ]H  }|j%                  t[        t]        |j^                  |j`                  |jb                  ¬$«      |¬%«      «       ŒJ t-        jd                  |Ž ƒ d{  –—†  Œy tg        | j                  |¬&«      ƒ d{  –—†  dd| j                  ii}|ji                  «       4 ƒd{  –—† }tk        | j                  «      D ]   }|jm                  tn        |«      ƒ d{  –—†  Œ" |jp                  js                  |¬«      ƒ d{  –—†  tu        | j                  |¬'«      ƒ d{  –—†  ddd«      ƒd{  –—†  d(| j                  i}tw        ||
|	¬)«      ƒ d{  –—†  |D ]!  }ty        ||j^                  ¬*«      ƒ d{  –—†  Œ# |S 7 �Œ�# t        $ r t        ddd|› �i¬«      ‚w xY w7 �Œq7 �ŒJ7 �Œ7 �ŒE7 �Œ27 �Œ7 �Œý7 �Œ×7 �Œ`7 �ŒB7 �Œ7 Œè7 ŒÄ7 Œ§7 Œ™# 1 ƒd{  –—†7  sw Y   Œ©xY w7 ŒŒ7 Œj­w)+a�  
    delete team and associated team keys

    Parameters:
    - team_ids: List[str] - Required. List of team IDs to delete. Example: ["team-1234", "team-5678"]

    ```
    curl --location 'http://0.0.0.0:4000/team/delete'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data-raw '{
        "team_ids": ["8d916b1c-510d-4894-a334-1c16a93344f5"]
    }'
    ```
    r   r  )r	  r
  r$  rJ  rI  Nr  r  r  rS  rÅ  r–  r•   r�  r‹  r—  rY  )r¼  r$  rî   r  rÐ  r  r  TrÑ   r>  Údeletedz{}r@  rI  rM  r³  )rO  r$  rî   r  rb  )Úteam_id_listr  ©rO  rI  rJ  )Údelete_team_models)r‰  )r±  r$  r‰  )r•   r¯   r¾  r‘  )r±  r$  )r±  r)  r  )r¼  rI  rJ  rœ  )=rK  r  r  rL  r	  r
  r$  rJ  rI  r   r±  r'  r  rC  r,   rM  r¹   rZ  r”  Ú_persist_deleted_team_recordsrQ  rÔ   r]  r^  r$   r¡   r   rw  r   r_  r   r`  ra  r/   rb  rR  rN  r>  r“  Údelete_dataÚ_invalidate_deleted_key_cacheÚ=litellm.proxy.management_endpoints.model_management_endpointsrŸ  r‰  rÙ   r]  rA   r•   r¯   r¾  r%  Ú_sweep_deleted_team_referencesr)  r  rø  re   r
  rQ  Ú!_sweep_deleted_team_references_txÚ_invalidate_deleted_team_cacheri   )rl  r  rî   r  r  r  r	  r
  r$  rJ  rI  Ú	team_rowsr•   Úteam_row_baseÚteam_row_pydanticrH  Ú	_team_rowrN  rZ  rŸ  r‰  r’  ÚtasksÚteam_memberÚdelete_filterr)  r  Údeleted_teams                               r�   Údelete_teamr¯    sÂ  è ø€ ÷4÷õ ð ÐÜ¨°WÐ>OÐ4PÔQÐQà‡}�}ÐÜ¨°WÐ>TÐ4UÔVÐVð 13€IØ—=‘=ò ,ˆð	Ü4<¸]Ó4K×4WÑ4WÐ_hÐjqÐ^rÐ4WÓ4s×.sˆMØÐ$Ü�ð %ô .×<Ñ<¸]×=UÑ=UÓ=WÓXÐô "Ø&Ø/ô
÷ 	
ð 	
ð
 	×ÑÐ*Õ+ð%,ô( (ØØ#Ø+Ø-ô	÷ ð ñ  Ô!à—}‘}ò 	ˆGØ7D×7MÑ7MØ¨F¸}ð 8Nó 8÷ 2ˆHð ÐØà Ÿ™°4˜Ó8ˆIä×ÑÙ+Ü!2ÜœtŸz™z›|Ó,Ü#+§<¡<´·±Ó#=Ù#;Ø/AØ.?Ø5Mô$ð
 ,=×+DÑ+DÜ#4×#DÑ#DØ")Ø(Ø'+Ø%.ô"ôõð	õDô #-¨]Ó";×"EÑ"EÈYÐY]Ð_c×_lÑ_lÐXmÐLnÐ"EÓ"o×o€NáÙ2ØØ'Ø/Ø1ô	
÷ 	
ð 	
ð ×
#Ñ
#°·±È5Ð
#Ó
Q×QÐQä
'ØØ-Ø+ô÷ ð õõ 6á
Ø—‘Ø#Øô÷ ð ð ò %ˆà×2Ñ2ˆàˆØ'ò 
	ˆKØ�L‰LÜ"Ü0Ø (× 0Ñ 0Ø +× 3Ñ 3Ø#.×#9Ñ#9ôð
 '8ôõ	ð
	ô �n‰n˜eÐ$×$Ñ$ð!%ô$ )°$·-±-È}Ô
]×]Ð]ð .7¸¸t¿}¹}Ð8MÐ,N€MØ×ÑÓ!÷ Oð O RÜ˜dŸm™mÓ,ò 	@ˆGØ—,‘,Ô5°wÓ?×?Ñ?ð	@à×"Ñ"×.Ñ.°]Ð.ÓC×CÐCÜ/¸¿¹È2ÔN×NÐN÷	O÷ Oð 2AÀ$Ç-Á-Ð0P€Mô )ØØ-Ø+ô÷ ð ð "ò kˆÜ/¸mÐUa×UiÑUiÔj×jÑjðkð Ððm /túô ò 	ÜØØÐ#BÀ7À)Ð!LÐMôð ð	úð	
ùðùð2ùðJ pùð	
ùð Rùðùðùð. 	%ùà]ùðOùà?øØCøØNøð	Oø÷ O÷ Oñ Oúðøð 	kús|  ‚AQ+Á P
Á7PÁ8P
Â4Q+Â8P)Â9)Q+Ã"P,Ã#1Q+ÄP/ÄCQ+Ç-P2Ç.Q+ÈP5È$Q+È(P8È)Q+È>P;È?(Q+É'P>É(A9Q+Ë!QË" Q+ÌQÌ(Q+Ì+QÌ,Q+Ì/2QÍ!Q
Í"%QÎQÎQÎ&QÎ'QÎ+Q+Î6QÎ7#Q+ÏQ'Ï#Q+Ï>Q)Ï?Q+ÐP
Ð
P&Ð&Q+Ð,Q+Ð/Q+Ð2Q+Ð5Q+Ð8Q+Ð;Q+Ð>Q+ÑQ+ÑQ+ÑQ+Ñ
QÑQÑQÑQ+ÑQ$ÑQÑQ$Ñ Q+Ñ)Q+c              ƒ   óâ   K  — | D ]*  }|j                   j                  t        |«      ƒ d{  –—† }Œ, t        |«      j	                  t        dt        | «      i¬«      ¬«      ƒ d{  –—† }y7 Œ?7 Œ­w)ai  
    Strip the deleted team ids from every user row and team-membership row that still references them.

    The per-member `team_member_delete` pass above only reaches users listed in the team's
    `members_with_roles`, so a user row that outlived its roster entry is invisible to it and keeps
    surfacing the team on `/user/info` after the team is gone.

    #36839 closed the route that created that drift, by resolving member removal off the roster
    entry's `user_id` rather than the identifier the caller happened to pass. It does not backfill
    rows that already drifted, which is the state this was reported against, so the sweep still has
    to run on delete.

    `array_remove` rather than read-filter-write: rewriting the whole array from a snapshot read
    outside a transaction drops any team a concurrent `/team/member_add` appended in between.
    Nr³  )r•   r�  )r[  r  r!  r-  rQ  r   rò  )r±  r$  r•   Ú_s       r�   r¤  r¤  ß  so   è ø€ ð  ò \ˆØ×"Ñ"×.Ñ.Ô/QÐSZÓ[×[‰ð\ô " -Ó0×<Ñ<Ä?Ð\`ÔbgÐhpÓbqÐ[rÔCsÐ<Ót×t�Að \øàtús!   ‚)A/«A+¬9A/Á%A-Á&A/Á-A/c              ƒ   óÄ   K  — | D ]   }|j                  t        |«      ƒ d{  –—† }Œ" ddt        | «      ii}|j                  j	                  |¬«      ƒ d{  –—† }y7 Œ:7 Œ­w)z°Same sweep as `_sweep_deleted_team_references`, run on the transaction that holds
    every id's advisory lock and deletes the team rows, so it commits or rolls back with them.Nr•   r³  r�  )r  r!  rò  r  rQ  )r±  r)  r•   r±  Úmembership_filters        r�   r¥  r¥  õ  sm   è ø€ ð ò NˆØ—.‘.Ô!CÀWÓM×M‰ðNð 2;¸TÄ5ÈÃ?Ð<SÐ0TÐØ×'Ñ'×3Ñ3Ð:KÐ3ÓL×L�Að Nøð 	Mús!   ‚A ¡A¢4A ÁAÁA ÁA rO  z1Sequence[prisma_models.LiteLLM_VerificationToken]c              ƒ   ó\   K  — t        t        d„ | D «       «      ||¬«      ƒ d{  –—†  y7 Œ­w)aA  
    Evict the auth cache entry for every key deleted along with the team.

    `/key/delete` evicts as it goes, but the bulk delete above writes straight to the db. Auth
    resolves a cached key object without re-reading the team, so a key belonging to a deleted team
    keeps buying access until its TTL expires.
    c              3   ó4   K  — | ]  }|j                   –— Œ y ­wr¥   )Útoken)rØ  rb  s     r�   rÙ  z0_invalidate_deleted_key_cache.<locals>.<genexpr>  s   è ø€ Ò6¨#˜CŸI�IÑ6ùs   ‚)Úhashed_tokensrI  rJ  N)rL   rò  rž  s      r�   r¢  r¢  ÿ  s.   è ø€ ô #ÜÑ6°Ô6Ó6Ø-Ø+ô÷ ò úó   ‚",¤*¥,c              ƒ   ó\   ‡‡K  — t        j                  ˆˆfd„| D «       Ž ƒ d {  –—† }y 7 Œ­w)Nc              3   ód   •K  — | ]'  }t        |j                  |j                  ‰‰¬ «      –— Œ) y­w))r•   rÈ   rI  rJ  N)rM   r•   rÈ   )rØ  rÐ  rJ  rI  s     €€r�   rÙ  z1_invalidate_deleted_team_cache.<locals>.<genexpr>  s9   øè ø€ ò 

ð ô %ØŸ™ØŸ?™?Ø#5Ø"3÷	ð ñ

ùs   ƒ-0)r]  r%  )r¼  rI  rJ  r±  s    `` r�   r¦  r¦    s0   ùè ø€ ô
 �n‰nô

ð ô

ð
÷ 
	�Að 
	ús   „ ,¤*¥,c           	      ó¸  — | sg S t        j                  t        j                  «      }g }| D ]«  }|j	                  «       }t        j                  i |¥||j                  |j                  |dœ¥«      }|j	                  «       }dD ](  }	|	|v sŒ||	   €Œt        j                  ||	   «      ||	<   Œ* dD ]  }
|j                  |
d«       Œ |j                  |«       Œ­ |S )z@Transform teams into deleted team records ready for persistence.)Ú
deleted_atÚ
deleted_byÚdeleted_by_api_keyr  )rÙ   rÎ   Úmodel_spendÚmodel_max_budgetr7  N)r"  rU  rA  rX  rÖ  )r   r_  r   r`  r¹   r%   rM  r¯   ra  rÔ   rT  ra  r”  )r¼  rî   r  r¼  ÚrecordsrÐ  Úteam_payloadÚdeleted_recordÚrecordÚ
json_fieldÚrel_keys              r�   Ú#_transform_teams_to_deleted_recordsrÇ  $  sÿ   € ñ Øˆ	ä Ÿ™¤X§\¡\Ó2€JØ€GØò  ˆØ—‘Ó(ˆÜ1×@Ñ@ðØðà(Ø/×7Ñ7Ø&7×&?Ñ&?Ø&8òó
ˆð  ×*Ñ*Ó,ˆð
ò 	DˆJð ˜VÒ#¨¨zÑ(:Ñ(FÜ%)§Z¡Z°°zÑ0BÓ%C��zÒ"ð	Dð
ò 	&ˆGð �J‰J�w Õ%ð	&ð 	�‰�vÕðA ðD €Nrœ   rÁ  c              ƒ   ó\   K  — | syt        |«      j                  | ¬«      ƒ d{  –—†  y7 Œ­w)z*Save deleted team records to the database.Nr~  )r9  r•  ©rÁ  r$  s     r�   Ú_save_deleted_team_recordsrÊ  T  s*   è ø€ ñ
 ØÜ
˜=Ó
)×
5Ñ
5¸7Ð
5Ó
C×CÒCúr¸  c              ƒ   óV   K  — t        | ||¬«      }t        ||¬«      ƒ d{  –—†  y7 Œ­w)z=Persist deleted team records by transforming and saving them.)r¼  rî   r  rÉ  N)rÇ  rÊ  )r¼  r$  rî   r  rÁ  s        r�   r   r   ^  s5   è ø€ ô 9ØØ+Ø-ô€Gô
 %ØØ#ô÷ ò ús   ‚)¡'¢)rL  c              ƒ   ó†  K  — | j                   t        j                  j                  k(  s'| j                   t        j                  j                  k(  ry | j
                  |j
                  k(  ry | j                  €R| j
                  �)t        ddd| j
                  › d|j
                  › �i¬«      ‚t        ddd|j
                  › d�i¬«      ‚| j                  |j                  D �cg c]  }|j                  ‘Œ c}v ry t        | |¬«      ƒ d {  –—† ry t        ddd	| j                  › d|j
                  › �i¬«      ‚c c}w 7 Œ3­w)
Nrö  r  zTeam key for team=z$ not authorized to access this team=rS  z+API key not authorized to access this team=z1. No user_id or team_id associated with this key.rR  zUser=)
rV  r0   rW  r¢   ÚPROXY_ADMIN_VIEW_ONLYr•   r¯   r   rÙ   r[   )rî   rL  r™  s      r�   Úvalidate_membershiprÎ  p  sn  è ø€ à×#Ñ#Ô'7×'CÑ'C×'IÑ'IÒIØ×&Ñ&Ô*:×*PÑ*P×*VÑ*VÒVàà× Ñ  J×$6Ñ$6Ò6Øð × Ñ Ð(Ø×$Ñ$Ð0ÜØàÐ1Ð2C×2KÑ2KÐ1LÐLpÐq{÷  rDñ  rDð  qEð  Fðôð ô  ØàÐJÈ:×K]ÑK]ÐJ^ð  _Pð  Qðôð ð × Ñ ¸
×8UÑ8UÖ$V°1 Q§Y£YÒ$VÑVØô )Ð;LÐWaÔb×bÐbØä
ØØ˜5Ð!2×!:Ñ!:Ð ;Ð;_Ð`j×`rÑ`rÐ_sÐtÐuôð ùò %Wð cús   ‚C!EÃ#D:Ã6EÄD?Ä4Er]  Úteam_info_response_objectc              ƒ   óÎ   K  — 	 t        |«      j                  d| i¬«      ƒ d {  –—† }|j                  d|i¬«      S 7 Œ# t        $ r t	        j
                  d| «       Y |S w xY w­w)Nrê   r�  r~  ræ  zCTeam member budget table not found, passed team_member_budget_id=%s)r7  r  rè  rC  r   r‡  )r]  r$  rÏ  Úteam_budgets       r�   Ú_add_team_member_budget_tablerÒ  ™  sx   è ø€ ð

Ü#-¨mÓ#<×#HÑ#HÐP[Ð]rÐOsÐ#HÓ#t×tˆØ(×3Ñ3Ð<VÐXcÐ;dÐ3ÓeÐeð uùäò 
Ü×!Ñ!ØQÐShõ	
ð %Ð$ð
üs1   ‚A%„ ? ¤=¥? ¼A%½? ¿A"ÁA%Á!A"Á"A%c              ƒ   óV  ‡K  — t        d„ |D «       «      }|st        |«      S t        | «      j                  ddt	        |«      ii¬«      ƒ d{  –—† }t        |D �ci c]&  }|j                  sŒ|j                  |j                  “Œ( c}«      Št        ˆfd„|D «       «      S 7 ŒSc c}w ­w)aÇ  Fill in ``user_email`` for roster entries that were stored without one.

    ``members_with_roles`` is a denormalized snapshot written at add-time, so an entry
    stored with ``user_email=None`` keeps that null even once the user row has an email.
    Look the missing ones up in ``LiteLLM_UserTable`` (one indexed query) and fill them
    in. A stored email is never overwritten - the snapshot stays the source of truth
    wherever it has a value.
    c              3   óh   K  — | ]*  }|j                   rŒ|j                  €Œ|j                  –— Œ, y ­wr¥   râ  rJ  s     r�   rÙ  z)_hydrate_member_emails.<locals>.<genexpr>µ  s&   è ø€ Ò'q°aÈ!Ï,Ë,Ð[\×[dÑ[dÑ[p¨¯	­	Ñ'qùs   ‚2”2¡2r¯   r³  r�  Nc              3   ó°   •K  — | ]M  }|j                   s;|j                  �/|j                  ‰v r!|j                  d‰|j                     i¬«      n|–— ŒO y ­w)Nr¾  ræ  )r¾  r¯   rè  )rØ  r™  Úemail_by_user_ids     €r�   rÙ  z)_hydrate_member_emails.<locals>.<genexpr>Â  s[   øè ø€ ò ð ð �|Š| §	¡	Ð 5¸!¿)¹)ÐGWÑ:Wð 	
�‰˜\Ð+;¸A¿I¹IÑ+FÐGˆÔHàó	ñùs   ƒAA)rŸ  rò  r/  r“  r  r   r¾  r¯   )r$  rƒ  Úmissing_user_idsÚ	user_rowsÚurÖ  s        @r�   Ú_hydrate_member_emailsrÚ  ©  sº   øè ø€ ô (Ñ'q¸7Ô'qÓqÐÙÜ�W‹~ÐäHPÐQ^ÓH_×HiÑHiàØ”fÐ-Ó.ðð
ð Ijó I÷ C€Iô /ÐQZÖ/kÈAÐ^_×^jÓ^j°·	±	¸1¿<¹<Ñ0GÒ/kÓlÐäó ð ô	ó ð ðCúò 0lùs*   ƒAB)ÁB"ÁB)ÁB$Á.B$ÂB)Â$B)Ú
_team_infoc              ƒ   óN  ‡K  — | j                   s| S t        | j                   «      ƒ d{  –—† Št        ˆfd„t        j	                  | j                   «      D «       «      }| j                  t        |D ��ch c]  }|j                  xs g D ]  }|’Œ Œ c}}«      t        |D ��ch c]  }|j                  xs g D ]  }|’Œ Œ c}}«      t        |D ��ch c]  }|j                  xs g D ]  }|’Œ Œ c}}«      t        d„ |D «       «      dœ¬«      S 7 Œæc c}}w c c}}w c c}}w ­w)zƒReturn a copy of the team info with access_group_models / mcp_server_ids /
    agent_ids / details resolved from its access groups.Nc              3   ó2   •K  — | ]  }|‰v sŒ‰|   –— Œ y ­wr¥   r›   ©rØ  Úag_idÚ	ag_lookups     €r�   rÙ  z7_resolve_team_access_group_resources.<locals>.<genexpr>Ò  s$   øè ø€ ò #Ø"ÐTYÐ]fÒTfˆ	�%Õñ#ùó   ƒ	�
c           	   3   óŽ   K  — | ]=  }t        |j                  |j                  t        |j                  xs d «      ¬«      –— Œ? y­w)r›   )Úaccess_group_idÚaccess_group_namer�   N)r;   rã  rä  rò  Úaccess_model_names)rØ  Úgroups     r�   rÙ  z7_resolve_team_access_group_resources.<locals>.<genexpr>Ü  sI   è ø€ ò *ð ô *Ø$)×$9Ñ$9Ø&+×&=Ñ&=Ü  ×!9Ñ!9Ò!?¸RÓ@÷ð ñ*ùs   ‚AA)Úaccess_group_modelsÚaccess_group_mcp_server_idsÚaccess_group_agent_idsÚaccess_group_detailsræ  )
Úaccess_group_idsÚ%_batch_resolve_access_group_resourcesrò  râ   Úfromkeysrè  r§  rå  Úaccess_mcp_server_idsÚaccess_agent_ids)rÛ  Úresolved_groupsræ  r™  ÚsÚarà  s         @r�   Ú$_resolve_team_access_group_resourcesró  Ê  s!  øè ø€ ð
 ×&Ò&ØÐÜBÀ:×C^ÑC^Ó_×_€IÜ"ó #Ü&*§m¡m°J×4OÑ4OÓ&Pô#ó €Oð × Ñ ä#'¸×(r¨uÐRW×RjÑRjÒRpÐnpÒ(rÈAªÐ(r¨Ó(rÓ#sÜ+/Ø /×]�u¸%×:UÑ:UÒ:[ÐY[Ò]°A’Ð]�Ó]ó,ô '+¸?×+s°%ÐUZ×UkÑUkÒUqÐoqÒ+sÈqªAÐ+s¨AÓ+sÓ&tÜ$)ñ *ð -ô*ó %ñ
ð !ó ð ð	 `úó )sùã]ùã+sùs:   ƒ'D%ªD«A
D%Á5DÂD%Â$DÃD%ÃDÃ1!D%ÄD%z
/team/infoz!Team ID in the request parameters)r=  r  z!Limit the number of keys returned)r=  r  Úgtre  c              ƒ   ó.  K  — ddl m} ddlm} 	 |€t	        t
        j                  ddi¬«      ‚|€t	        t
        j                  dd	i¬«      ‚	 t        |«      j                  d
|idddœ¬«      ƒ d{  –—† }|€t        ‚	 t        |t        j                  |j                  «       «      ¬«      ƒ d{  –—†  |j!                  |ddt#        j$                  «       |¬«      ƒ d{  –—† }|€g }|€d}|D ]  }	|t'        |	dd«      z  }Œ d|i}|D ]%  }
	 |
j                  «       }
|
j+                  dd«       Œ' t-        ||gd¬«      ƒ d{  –—† }t/        |t(        «      r |j                  |«      }n8t/        |t0        «      r! |j                  |j                  «       «      }n |«       }|j2                  �|j2                  j5                  d«      nd}|�t7        |||¬«      ƒ d{  –—† }t9        |«      ƒ d{  –—† }t;        ||j<                  ¬«      ƒ d{  –—† }|j?                  dtA        |«      i¬«      }tC        ||||¬«      }|S 7 �ŒÔ# t        $ r" t	        t
        j                  dd|› d�i¬«      ‚w xY w7 �ŒÆ7 �Œ™# t        $ r |
j)                  «       }
Y �Œzw xY w7 �ŒX7 Œ¾7 Œ­7 Œ�# t        $ râ}tE        jF                  d|tI        jJ                  «       «       t/        |t        «      rPtM        t'        |dd|› d �«      tN        jP                  t'        |d!d"«      t'        |d#t
        jR                  «      ¬$«      ‚t/        |tL        «      r|‚tM        d%tU        |«      z   tN        jP                  t'        |d!d"«      t
        jR                  ¬$«      ‚d}~ww xY w­w)&a#  
    get info on team + related keys

    Parameters:
    - team_id: str - Required. The unique identifier of the team to get info on.

    ```
    curl --location 'http://localhost:4000/team/info?team_id=your_team_id_here'     --header 'Authorization: Bearer your_api_key_here'
    ```
    r   )r>   r&  Nr  ú�Database not connected. Connect a database to your proxy - https://docs.litellm.ai/docs/simple_proxy#managing-auth---virtual-keysrS  rÄ  z(Malformed request. No team id passed in.r•   Trš  rµ  z Team not found, passed team id: r÷  )rî   rL  rb  r*  )r•   r  r  ÚexpiresÚlimitrz  r¶  r   r]  )r]  r$  rÏ  )r$  rƒ  rÙ   ræ  )r•   rf  rO  r¸  z\litellm.proxy.management_endpoints.team_endpoints.py::team_info - Exception occurred - %s
%srU  zAuthentication Error(r  rÆ  ÚNonerT  rÃ  zAuthentication Error, )+ru  r>   rL  r$  r   r   rƒ  ÚHTTP_422_UNPROCESSABLE_ENTITYr'  r  rC  r„  rÎ  r,   rM  r¹   rQ  r   r_  r¦  râ   ra  r»  r_  r   rÎ   r{  rÒ  ró  rÚ  rÙ   rè  r§  r=   r   r  Ú	tracebackÚ
format_excr6   r5   Ú
auth_errorry  r¡   )r  r•   re  rî   r>   r$  rf  rO  rz  Úkrb  r¹  rÛ  r]  Úresolved_team_infoÚhydrated_membersÚhydrated_team_infoÚresponse_objectrv  s                      r�   rf  rf  è  sõ  è ø€ õ& EÝ8ð|
ØÐ ÜÜ"×AÑAàð  aðôð ð ˆ?ÜÜ"×@Ñ@Ø!Ð#MÐNôð ð
	Ü08¸Ó0G×0SÑ0SØ  'Ð*Ø04È4ÑPð 1Tó 1÷ +ˆIð Ð Ü�ð !ô "Ø/Ü(×7Ñ7¸	×8LÑ8LÓ8NÓOô
÷ 	
ð 	
ð #×+Ñ+ØØØ!Ü—L‘L“NØð ,ó 
÷ 
ˆð ˆ<ØˆDàÐàˆEØò 0�Øœ  G¨QÓ/Ñ/‘ð0à  %Ð(ˆIð ò 	#ˆCð!Ø—n‘nÓ&�ð �G‰G�G˜TÕ"ð	#ô $<¸MÈGÈ9Ð^bÔ#c×cˆä�i¤Ô&ØGÐ8×GÑGÈ	ÓR‰JÜ˜	¤9Ô-ØGÐ8×GÑGÈ	×H\ÑH\ÓH^Ó_‰Já8Ó:ˆJð AK×@SÑ@SÐ@_ˆJ×Ñ×#Ñ#Ð$;Ô<Ðeið 	ð !Ð,Ü<Ø&;Ø+Ø*4ô ÷ ˆJô +OÈzÓ*Z×$ZÐô )?Ø'Ø&×9Ñ9ô)
÷ #
Ðð %7×$AÑ$Að %¤dÐ+;Ó&<ðð %Bó %
Ðô "8ØØ(ØØ(ô	"
ˆð Ððo+úô ò 	ÜÜ"×5Ñ5Ø!Ð%EÀgÀYÈaÐ#PÐQôð ð	úð
	
ùð
úô, ò !à—h‘h“j“ð!úð dùðøð %[øð#
ùô( ò 
Ü×"Ñ"ØkØÜ× Ñ Ó"ô	
ô
 �aœÔ'Ü Ü  8Ð/DÀQÀCÀqÐ-IÓJÜ$×/Ñ/Ü˜a ¨&Ó1Ü˜Q ¬v×/JÑ/JÓKô	ð ô ˜œ>Ô*ØˆGÜØ,¬s°1«vÑ5Ü ×+Ñ+Ü˜!˜W fÓ-Ü×,Ñ,ô	
ð 	
ûð
üsØ   ‚N�>J' Á$I
 Á3IÁ4I
 Â 2J' Â2I8Â3/J' Ã"I;Ã#,J' ÄI>Ä &J' ÅJÅBJ' Ç"J!Ç#J' Ç5J#Ç6J' ÈJ%È1J' ÉNÉI
 É
+I5É5J' É;J' É>JÊJ' ÊJÊJ' Ê!J' Ê#J' Ê%J' Ê'	NÊ0CNÎNÎNz/team/{team_id}/members/mec              ƒ   óL  K  — ddl m}m} |€t        t        j
                  ddi¬«      ‚|j                  }|€t        t        j                  ddi¬«      ‚t        |||¬«      ƒ d{  –—† }|j                  }d}|j                  D ]J  }	|	j                  �|	j                  |k(  s |	j                  €Œ+|€Œ.|	j                  |k(  sŒ>|	j                  } n |€$t        t        j                  dd	|› d
|› d�i¬«      ‚t        ||||¬«      ƒ d{  –—† }
t        |||d¬«      ƒ d{  –—† }|�t        |dd«      nd}|
€t!        |||j"                  ||dddd¬«	      S t!        |||j"                  |||
j$                  |
j&                  |
j(                  |
j*                  ¬«	      S 7 �Œ77 Œ•7 Œ€­w)u  
    Get the caller's own team-membership row for the given team.

    Used by internal users to view their own spend, budget, budget reset
    date, rate limits, and role within a team â€” without exposing other
    members' data. The caller is resolved from their API key; the path
    `/members/me` always refers to that caller.

    Returns 404 if the caller is not a member of the team.

    ```
    curl --location 'http://localhost:4000/team/your_team_id/members/me'     --header 'Authorization: Bearer your_api_key_here'
    ```
    r   )r$  rI  Nr  rö  rS  zKAPI key has no associated user_id; cannot resolve 'me' for team membership.)r•   r$  rI  zUser user_id=z is not a member of team_id=r÷  )r¯   r•   r$  rI  Frï  r¾  rx  )	r¯   r•   rÈ   r#  r¾  rz  Útotal_spendrê   r´  )rL  r$  rI  r   r   rƒ  r¯   ry  rP   r¾  rÙ   r#  r„  rO   rQ   r¦  rŒ   rÈ   rz  r  rê   r´  )r  r•   rî   r$  rI  rÒ  rL  Úcaller_user_emailÚmember_roler™  rv  Úuser_rowr¾  s                r�   Úteam_member_mer  }  s	  è ø€ ÷6 MàÐÜÜ×=Ñ=àð  ]ðô
ð 	
ð .×5Ñ5€NØÐäÜ×3Ñ3ØÐjÐkô
ð 	
ô
 .ØØ#Ø-ô÷ €Jð  1×;Ñ;ÐØ"€KØ×*Ñ*ò ˆð �I‰IÐ! a§i¡i°>Ò&AØ�L‰LÑ$Ð):Ñ)FÈ1Ï<É<Ð[lÓKlàŸ&™&ˆKÙðð Ðô Ü×1Ñ1Ø˜}¨^Ð,<Ð<XÐY`ÐXaÐabÐcÐdô
ð 	
ô
 2ØØØ#Ø-ô	÷ €Jô ,ØØ#Ø-Øô	÷ €Hð BJÐAUœ ¨,¸Ô=Ð[_€JàÐô &Ø"ØØ!×,Ñ,ØØ!ØØØØ!%ô

ð 
	
ô "ØØØ×(Ñ(ØØØ×ÑØ×*Ñ*Ø×&Ñ&Ø'×<Ñ<ô
ð 
ðqùð4øðúsK   ‚A$F$Á&FÁ'AF$Â0F$Â3F$ÃAF$Ä
F ÄF$Ä!F"Ä"A<F$Æ F$Æ"F$z/team/blockc              ƒ   óª  K  — ddl m} |€t        d«      ‚t        |«      j	                  d| j
                  i¬«      ƒ d{  –—† }|€t        ddd	| j
                  › �i¬
«      ‚t        t        j                  |j                  «       «      |¬«      ƒ d{  –—†  t        |«      j                  d| j
                  iddi¬«      ƒ d{  –—† }|S 7 ŒŒ7 Œ:7 Œ
­w)a¶  
    Blocks all calls from keys with this team id.

    Parameters:
    - team_id: str - Required. The unique identifier of the team to block.

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

    Returns:
    - The updated team record with blocked=True



    r   r&  NúNo DB Connected.r•   r�  r‹  r  r—  rS  rY  ÚblockedTr’  ©rL  r$  rC  r'  r  r•   r   rZ  r,   rM  r¹   r  ©rl  r  rî   r$  Úexisting_teamrÄ  s         r�   Ú
block_teamr  ï  sê   è ø€ õ: 9àÐÜÐ*Ó+Ð+ä!)¨-Ó!8×!DÑ!DÈIÐW[×WcÑWcÐKdÐ!DÓ!e×e€MØÐÜØØÐ>¸t¿|¹|¸nÐMÐNô
ð 	
ô Ü"×1Ñ1°-×2JÑ2JÓ2LÓMØ+ô÷ ð ô
 # =Ó1×8Ñ8Ø˜$Ÿ,™,Ð'Ø˜Ðð 9ó ÷ €Fð
 €Mð% føðøð
úó6   ‚>CÁ CÁACÂCÂ1CÃCÃCÃCÃCz/team/unblockc              ƒ   óª  K  — ddl m} |€t        d«      ‚t        |«      j	                  d| j
                  i¬«      ƒ d{  –—† }|€t        ddd	| j
                  › �i¬
«      ‚t        t        j                  |j                  «       «      |¬«      ƒ d{  –—†  t        |«      j                  d| j
                  iddi¬«      ƒ d{  –—† }|S 7 ŒŒ7 Œ:7 Œ
­w)až  
    Unblocks a previously blocked team, re-enabling calls from keys with this team id.

    Parameters:
    - team_id: str - Required. The unique identifier of the team to unblock.

    Example:
    ```
    curl --location 'http://0.0.0.0:4000/team/unblock'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "team_id": "team-1234"
    }'
    ```
    r   r&  Nr
  r•   r�  r‹  r  r—  rS  rY  r  Fr’  r  r  s         r�   Úunblock_teamr  &  sê   è ø€ õ. 9àÐÜÐ*Ó+Ð+ä!)¨-Ó!8×!DÑ!DÈIÐW[×WcÑWcÐKdÐ!DÓ!e×e€MØÐÜØØÐ>¸t¿|¹|¸nÐMÐNô
ð 	
ô Ü"×1Ñ1°-×2JÑ2JÓ2LÓMØ+ô÷ ð ô
 # =Ó1×8Ñ8Ø˜$Ÿ,™,Ð'Ø˜Ðð 9ó ÷ €Fð
 €Mð% føðøð
úr  z/team/metadata_schemac               ƒ   óF   K  — t        t        j                  «       ¬«      S ­w)a[  
    Get the team metadata fields declared in ``general_settings.team_metadata_schema``.

    The UI uses this to prepopulate the team metadata form with the declared
    keys. Returns an empty ``fields`` list when no schema is configured. This
    schema is advisory; server-side enforcement stays with
    ``custom_team_metadata_validate``.
    )Úfields)r�   rn   r{  r›   rœ   r�   Úget_team_metadata_schemar  W  s   è ø€ ô &Ô-J×-NÑ-NÓ-PÔQÐQùs   ‚!z/team/availablec              ƒ   óÒ  K  — ddl m} |€'t        ddt        j                  j
                  i¬«      ‚t        t        t           d z  t        j                  �t        j                  j                  d«      nd «      }|€g S t        |«      j                  d|j                  i¬«      ƒ d {  –—† }|€t        d	dd
i¬«      ‚t        j                   |j#                  «       «      }|D �cg c]  }||j$                  vsŒ|‘Œ }}t'        |«      j)                  dd|ii¬«      ƒ d {  –—† }|D �cg c]%  }t+        j                   |j#                  «       «      ‘Œ' }	}|	S 7 Œ¯c c}w 7 Œ=c c}w ­w)Nr   r&  rÅ  r  rS  r­  r¯   r�  r‹  zUser not foundr•   r³  )rL  r$  r   r"   r�  r¢   r   r§  r¡   r¤  r®  r{  r/  r  r¯   r.   rM  r¹   r¼  r'  r“  r,   )
r  rî   r   r$  r­  Ú	user_infoÚuser_info_correct_typerÐ  Úavailable_teams_dbÚavailable_teams_correct_types
             r�   Úlist_available_teamsr  i  sp  è ø€ õ 9àÐÜØØÔ.×EÑE×KÑKÐLô
ð 	
ô
 ÜŒS‰	�DÑô ×3Ñ3Ð?ô ×0Ñ0×4Ñ4Ð5FÔGàó€Oð ÐØˆ	ô & mÓ4×@Ñ@È	ÐSd×SlÑSlÐGmÐ@Ón×n€IØÐÜØØÐ-Ð.ô
ð 	
ô %6×$DÑ$DÀY×EYÑEYÓE[Ó$\Ðà(7Öd ¸4ÐG]×GcÑGcÒ;c’tÐd€OÐdä&.¨}Ó&=×&GÑ&GÈyÐ[_ÐapÐZqÐNrÐ&GÓ&s× sÐàdvÖ#wÐ\`Ô$5×$DÑ$DÀTÇ_Á_ÓEVÕ$WÐ#wÐ Ð#wà'Ð'ð oúò eà súâ#wùsH   ‚B'E'Â)EÂ*<E'Ã&EÃ:EÃ>$E'Ä"E Ä#E'Ä+*E"ÅE'ÅE'Å"E'c              ƒ   ó.  K  — 	 t        | ||d|¬«      ƒ d{  –—† }|€y|j                  xs g D �cg c]A  }|j                  t        j
                  j                  k(  r|j                  �|j                  ‘ŒC }}|r|S dS 7 Œg# t        $ r Y yw xY wc c}w ­w)z¶
    Return the list of organization IDs where the user is an org admin.
    Returns None if the user is not an org admin of any organization or if
    the user cannot be found.
    F©r¯   r$  rI  rð  rJ  N)rQ   r·  Úorganization_membershipsrV  r0   rž  r¢   rÛ   )r¯   r$  rI  rJ  Úcaller_userr™  Úorg_idss          r�   Ú_get_org_admin_org_idsr!  ”  s´   è ø€ ð
Ü#2ØØ'Ø1Ø Ø/ô$
÷ 
ˆð ÐØð ×6Ñ6Ò<¸"öàØ�;‰;Ô*×4Ñ4×:Ñ:Ò:¸q×?PÑ?PÐ?\ð 	
×Óð€Gð ñ
 ˆ7Ð' 4Ð'ð'
ùô ò áðüòùsC   ‚B„B —A?˜B œB±ABÁ7BÁ?B Â	BÂ
BÂBÂBÚexactrÈ   Úuse_deleted_tableÚsearchÚsearch_team_id_matchÚorg_admin_org_idsc              ƒ   óª  K  — i }|r||d<   |r|ddœ|d<   |r|dk(  rdd|iind|id|ddœig|d<   |r||d<   n	|�d
|i|d<   |rl	 t        || |	d|
¬«      ƒ d	{  –—† }|€t        ddd|› �i¬«      ‚|j                  xs g }|r	d|i|d<   |S |sy	|�||vrt        ddd|› �i¬«      ‚|S d
|i|d<   |S 7 ŒY# t        $ r t        ddd|› �i¬«      ‚w xY w­w)zÐ
    Build where conditions for team list query.

    Returns None when the query is guaranteed to yield no results (e.g. user
    has no team memberships), allowing the caller to skip the DB round-trip.
    r•   r,  ©Úcontainsr.  rÈ   ÚprefixÚ
startsWithÚORrÛ   Nr³  Fr  r‹  r  zUser not found, passed user_id=rS  Úhasrƒ  z User is not a member of team_id=)rQ   r·  r   r¼  )r$  r•   rÈ   rÛ   r¯   r#  r$  r%  r&  rI  rJ  Úwhere_conditionsÚuser_object_correct_typeÚuser_team_idss                 r�   Ú!_build_team_list_where_conditionsr1  ¶  sŸ  è ø€ ð& 24ÐáØ&-Ð˜Ñ#áà"Ø!ñ*
Ð˜Ñ&ñ
 à4HÈHÒ4Tˆi˜,¨Ð/Ñ0Ð[dÐflÐZmØ¨¸ÑFÐGð"
Ð˜Ññ
 Ø.=ÐÐ*Ò+Ø	Ð	&à/3Ð5FÐ.GÐÐ*Ñ+áð	Ü4CØØ+Ø#5Ø$Ø"3ô5÷ /Ð$ð $Ð+ÜØØÐ#BÀ7À)Ð!LÐMôð ð  8×=Ñ=ÒCÀˆáØ+0°'Ð*:Ð˜YÑ'ð$ Ðñ !ØØÐ$à -Ñ/Ü'Ø$'Ø 'Ð+KÈGÈ9Ð)UÐVôð ð Ðð 04°]Ð.CÐ  Ñ+àÐðM/ùô ò 	ÜØØÐ#BÀ7À)Ð!LÐMôð ð	üs1   ‚ACÁB4 ÁB2ÁB4 ÁACÂ2B4 Â4CÃCÚall_access_group_idsz1dict[str, prisma_models.LiteLLM_AccessGroupTable]c              ƒ   óÜ   K  — ddl m} | r|€i S t        t        | «      «      }t	        |«      j                  dd|ii¬«      ƒ d{  –—† }|D �ci c]  }|j                  |“Œ c}S 7 Œc c}w ­w)z“
    Batch-fetch access groups in a single DB query and return them keyed by
    access_group_id. Missing/invalid groups are silently omitted.
    r   r&  Nrã  r³  r�  )rL  r$  rò  rŸ  r<  r“  rã  )r2  Ú_prisma_clientÚ
unique_idsr§   Úrows        r�   rì  rì    s~   è ø€ õ Ká >Ð#9Øˆ	äœiÐ(<Ó=Ó>€JÜ(¨Ó8×BÑBØ  4¨Ð"4Ð5ð Có ÷ €Dð 15Ö5¨ˆC×Ñ Ñ$Ò5Ð5ðúò 6ùs$   ‚AA,ÁA%ÁA,ÁA'Á"A,Á'A,Úkeys_count_by_teamc           
      óÀ  — g }|xs i }| D ]±  }	 |j                  «       }|r%|j                  t	        j
                  |«      «       Œ;|j                  d«      }t        |t        «      sg }||d<   t        |«      }|j                  |j                  d«      xs dd«      }	|j                  t        di |¤||	dœ¤Ž«       Œ³ |S # t        $ r |j                  «       }Y Œ½w xY w)z0Convert raw Prisma team rows to response models.rÙ   r•   rA  r   )Úmembers_countÚ
keys_countr›   )r¹   rC  râ   r”  r%   rM  r{  r_  r§  r–  r‰   )
r¼  r#  r7  Ú	team_listÚcountsrÐ  Ú	team_dictrÙ   r9  r:  s
             r�   Ú!_convert_teams_to_response_modelsr>    sö   € ð []€IØ&Ò,¨"€FØò ˆð	$ØŸ™Ó)ˆIñ Ø×ÑÔ5×DÑDÀYÓOÕPà!*§¡Ð/CÓ!DÐÜÐ0´$Ô7Ø%'Ð"Ø2D�	Ð.Ñ/ÜÐ 2Ó3ˆMØŸ™ I§M¡M°)Ó$<Ò$BÀÀAÓFˆJØ×ÑÜñ Øðà"/Ø)óõðð, Ðøô' ò 	$ØŸ	™	›ŠIð	$ús   �CÃCÃCc           	   ƒ   ór  K  — |D �cg c]  }t        |dd«      sŒt        |dd«      ‘Œ }}|si S t        dt        | «      j                  dgdd|iiddi¬«      ƒ d{  –—† «      }|D �ci c]:  }|j	                  d«      sŒ|d   |j	                  di «      j	                  dd«      “Œ< c}S c c}w 7 ŒSc c}w ­w)	a6  Aggregate virtual-key counts per team for the given page of teams.

    Runs a single GROUP BY against LiteLLM_VerificationToken. The IN clause is
    bounded by page_size and uses the existing @@index([team_id]), so this is
    one DB round-trip per page. Returns an empty map when the page has no teams.
    r•   NzSequence[_TeamIdGroupRow]r³  T)Úbyr�  rO  r    r   )r¦  r   r>  Úgroup_byr{  )r$  r¼  ÚtÚpage_team_idsÚgroupedr6  s         r�   Ú_get_keys_count_by_teamrE  ?  sÖ   è ø€ ð BGÖf¸AÌ'ÐRSÐU^Ð`dÕJeœG A y°$Õ7Ðf€MÐfÙØˆ	äØ#Ü˜Ó'×0Ñ0Øˆ{Ø˜t ]Ð3Ð4Ø˜dÐ#ð 1ó 
÷ 	
ó€Gð PWÖmÈÐZ]×ZaÑZaÐbkÕZlˆC�	‰N˜CŸG™G H¨bÓ1×5Ñ5°iÀÓCÑCÒmÐmùò gð	
úò nùs8   ‚B7‡B+šB+©3B7ÁB0
ÁB7Á)B2Â (B2Â(	B7Â2B7c              ƒ   ó¤  K  — t        | «      }d}|r||fS | j                  r!t        | j                  |||¬«      ƒ d{  –—† }|�N|r||vrt        dddi¬«      ‚|�|| j                  k(  rd}t	        j
                  d| j                  ||«       ||fS t        | |¬«      st        d	dd
| j                  › �i¬«      ‚|€| j                  }||fS 7 Œ�­w)a  Enforce access control for list_team_v2.

    - Proxy admins and admin viewers can query any teams.
    - Org admins can query teams within their organizations.
    - Regular users can only query their own teams.

    Returns the (possibly overridden) user_id and org_admin_org_ids.
    N)r¯   r$  rI  rJ  rö  r  z2You can only view teams within your organizations.rS  zIlist_team_v2: org admin access for user=%s, org_ids=%s, user_id_filter=%s)rî   Úrequested_user_idé‘  úAOnly admin users can query all teams/other teams. Your user role=)ra   r¯   r!  r   r   r†  rJ   rV  )rî   r¯   rÛ   r$  rI  rJ  r/  r&  s           r�   Ú_enforce_list_team_v2_accessrJ  X  s%  è ø€ ô  1Ð1BÓC€NØ*.ÐáØÐ)Ð)Ð)ð × Ò Ü"8Ø%×-Ñ-Ø'Ø1Ø/ô	#
÷ 
Ðð Ð$á˜Ð6GÑGÜØØÐ!UÐVôð ð ˆ?˜gÐ):×)BÑ)BÒBØˆGÜ×"Ñ"ØWØ×%Ñ%ØØô		
ð& Ð%Ð%Ð%ô 0ÐBSÐgnÕoÜØàÐ`Ðar×a|Ña|Ð`}Ð~ðôð ð ˆ?Ø'×/Ñ/ˆGàÐ%Ð%Ð%ðS
ús   ‚<C¾C¿BCz/v2/team/list)rþ  r   rÿ  z1Only return teams which this 'user_id' belongs toz9Only return teams which this 'organization_id' belongs toz1Only return teams which this 'team_id' belongs tozPOnly return teams which this 'team_alias' belongs to. Supports partial matching.zvCombined search: matches teams whose 'team_id' matches the value OR whose 'team_alias' contains it (case-insensitive).rÈ  zPage number for pagination)r=  r  ÚgezNumber of teams per pageéd   )r=  r  rK  Úlez>Column to sort by (e.g. 'team_id', 'team_alias', 'created_at')ÚasczSort order ('asc' or 'desc')z!Filter by status (e.g. 'deleted')z`How 'search' matches 'team_id': 'exact' (default) or 'prefix' for a case-sensitive prefix match.ÚpageÚ	page_sizeÚsort_byÚ
sort_orderr   c              ƒ   óö  ‡%K  — ddl m}m}m} |€t	        ddd|› �i¬«      ‚t        ||||||¬«      ƒ d{  –—† \  }}|�|d	k7  rt	        d
ddi¬«      ‚|d	k(  }|dz
  |z  }t        |||||||||||¬«      ƒ d{  –—† }|€g d||ddœS g d¢}d}|	r*|	|v r&|
j                  «       dvrd}
|	|
j                  «       i}|rPt        |«      j                  ||||r|nddi¬«      ƒ d{  –—† }t        |«      j                  |¬«      ƒ d{  –—† }nOt        |«      j                  ||||r|nddi¬«      ƒ d{  –—† }t        |«      j                  |¬«      ƒ d{  –—† }| |z   }i }|st        ||«      ƒ d{  –—† }t        |||¬«      }|�s1|D �cg c]"  }t        |t        «      sŒ|j                   sŒ!|‘Œ$ }}|�r|D ��cg c]  }|j                   xs g D ]  }|‘Œ Œ }}}t#        |«      ƒ d{  –—† Š%|D ]Ã  }t%        ˆ%fd„|j                   xs g D «       «      } t'        | D �!�"ch c]  }!|!j(                  xs g D ]  }"|"’Œ Œ c}"}!«      |_        t'        | D �!�#ch c]  }!|!j,                  xs g D ]  }#|#’Œ Œ c}#}!«      |_        t'        | D �!�$ch c]  }!|!j0                  xs g D ]  }$|$’Œ Œ c}$}!«      |_        ŒÅ |||||dœS 7 �Œ�7 �ŒN7 �Œç7 �ŒÇ7 �Œ�7 �Œ}7 �Œac c}w c c}}w 7 Œôc c}"}!w c c}#}!w c c}$}!w ­w)aU  
    Get a paginated list of teams with filtering and sorting options.

    Parameters:
        user_id: Optional[str]
            Only return teams which this user belongs to
        organization_id: Optional[str]
            Only return teams which belong to this organization
        team_id: Optional[str]
            Filter teams by exact team_id match
        team_alias: Optional[str]
            Filter teams by partial team_alias match
        page: int
            The page number to return
        page_size: int
            The number of items per page
        sort_by: Optional[str]
            Column to sort by (e.g. 'team_id', 'team_alias', 'created_at')
        sort_order: str
            Sort order ('asc' or 'desc')
        status: Optional[str]
            Filter by status. Currently supports "deleted" to query deleted teams.
    r   r  Nr  r  zNo db connected. prisma client=rS  )rî   r¯   rÛ   r$  rI  rJ  rœ  rÅ  z<Invalid status value. Currently only 'deleted' is supported.rÈ  )r$  r•   rÈ   rÛ   r¯   r#  r$  r%  r&  rI  rJ  )r¼  rü   rO  rP  Útotal_pages)r•   rÈ   r�  )rN  r�  rN  r�  r�  ©r�  rù   rø   rú   r�  )r7  c              3   ó2   •K  — | ]  }|‰v sŒ‰|   –— Œ y ­wr¥   r›   rÞ  s     €r�   rÙ  zlist_team_v2.<locals>.<genexpr>D  s$   øè ø€ ò $Ø).ÐX]ÐajÒXj�I˜eÕ$ñ$ùrá  )rL  r$  rJ  rI  r   rJ  r1  Úlowerr9  r“  rO  r'  rE  r>  r_  r‰   rë  rì  rò  r§  rå  rç  rî  rè  rï  ré  )&r  r¯   rÛ   r•   rÈ   r$  r%  rO  rP  rQ  rR  r   rî   r$  rJ  rI  r&  r#  rù   r.  Úvalid_sort_columnsÚorder_byr¼  Útotal_countrT  r7  r;  rB  Úteam_items_with_agrß  Ú
all_ag_idsÚ	team_itemÚteam_groupsræ  r™  rñ  rò  rà  s&                                        @r�   Úlist_team_v2r_  �  sÇ  øè ø€ ÷|ñ ð ÐÜØØÐ>¸}¸oÐNÐOô
ð 	
ô (DØ+ØØ'Ø#Ø-Ø+ô(÷ "Ñ€GÐð Ð˜f¨	Ò1ÜØØÐ[Ð\ô
ð 	
ð
  &¨Ñ2Ðð ˜!‘8˜yÑ(€Dô %FØ#ØØØ'ØØ+ØØ1Ø+Ø-Ø+ô%÷ Ðð ÐàØØØ"Øñ
ð 	
ò !HÐØ€HÙ�7Ð0Ñ0Ø×ÑÓ _Ñ4ØˆJØ˜Z×-Ñ-Ó/Ð0ˆñ Ü& }Ó5×?Ñ?Ø"ØØÙ&‘(¨\¸6Ð,Bð	 @ó 
÷ 
ˆô -¨]Ó;×AÑAÐHXÐAÓY×Y‰ä˜}Ó-×7Ñ7Ø"ØØÙ&‘(¨\¸6Ð,Bð	 8ó 
÷ 
ˆô % ]Ó3×9Ñ9Ð@PÐ9ÓQ×Qˆð (˜<¨9Ñ4Ð5€Kð *,ÐÙÜ#:¸=È%Ó#P×PÐô 2°%Ð9JÐ_qÔr€Iò Ø09Ö$p¨1¼ZÈÌ<Õ=XÐ]^×]oÓ]o¢QÐ$pÐÐ$pÚØ0B× k¨1ÐQR×QcÑQcÒQiÐgiÒ kÀu¢Ð k Ð kˆJÑ kÜ%JÈ:Ó%V×VˆIØ/ò �	Ü#ó $Ø3<×3MÑ3MÒ3SÐQSô$ó �ô 15Ø$/×Z˜5¸%×:RÑ:RÒ:XÐVXÒZ°A’QÐZ�QÓZó1�	Ô-ô 9=Ø$/×]˜5¸%×:UÑ:UÒ:[ÐY[Ò]°A’QÐ]�QÓ]ó9�	Ô5ô 48Ø$/×X˜5¸%×:PÑ:PÒ:VÐTVÒX°A’QÐX�QÓXó4�	Õ0ðð ØØØØ"ñð ðS"ùð,ùðB
ùð Zùð
ùð Rùð Qûò %qùã kØVúó [ùó ^ùó YùsÝ   ƒ3K9¶K·AK9Á:KÁ;A)K9Ã$KÃ%"K9ÄKÄ,K9Ä4KÄ5"K9ÅKÅK9Å6KÅ7K9ÆKÆ&KÆ3KÆ7
K9ÇKÇK9Ç0K%Ç15K9È&K'ÉK9ÉK-É9K9ÊK3Ê.K9ËK9ËK9ËK9ËK9ËK9ËK9ËK9Ë'K9c              ƒ   ó:  ‡K  — t        | «      }d}|sÓ‰duxr | j                  duxr | j                  ‰k(  }| j                  �‚t        | j                  ||d|¬«      ƒ d{  –—† }|�^|j                  xs g D �	cg c]A  }	|	j                  t
        j                  j                  k(  r|	j                  �|	j                  ‘ŒC }}	|sd}|€|st        ddd| j                  › �i¬«      ‚|�zt        t        |«      «      j                  dd	|iid
di¬«      ƒ d{  –—† }
‰st        |
«      S |
D �cg c].  }|j                  r t        ˆfd„|j                  D «       «      r|‘Œ0 c}S ‰rht        t        |«      «      j                  d
di¬«      ƒ d{  –—† }|D �cg c].  }|j                  r t        ˆfd„|j                  D «       «      r|‘Œ0 c}S t        t        t        |«      «      j                  d
di¬«      ƒ d{  –—† «      S 7 �Œ¢c c}	w 7 Œôc c}w 7 Œ„c c}w 7 Œ­w)a/  
    Authorize the /team/list request and return filtered teams.

    - Proxy admins: all teams (or filtered by user_id if provided).
    - Org admins: teams from their orgs (scoped to user_id if provided).
    - Own query (user_id matches caller): teams the user is a member of.
    - Others: 401.
    NFr  rH  r  rI  rS  rÛ   r³  r"  Trµ  c              3   óF   •K  — | ]  }|j                  d «      ‰k(  –— Œ y­w©r¯   N©r{  ©rØ  r™  r¯   s     €r�   rÙ  z._authorize_and_filter_teams.<locals>.<genexpr>—  ó   øè ø€ Ò.lÈq¨q¯u©u°YÓ/?À7Õ/JÑ.lùó   ƒ!)r¶  c              3   óF   •K  — | ]  }|j                  d «      ‰k(  –— Œ y­wrb  rc  rd  s     €r�   rÙ  z._authorize_and_filter_teams.<locals>.<genexpr>¡  re  rf  )ra   r¯   rQ   r  rV  r0   rž  r¢   rÛ   r   ræ   r~   r“  r§  rÙ   ri  )rî   r¯   r$  rI  rJ  r/  Úallowed_org_idsÚis_own_queryr  r™  Ú	org_teamsrÐ  rˆ  s    `           r�   Ú_authorize_and_filter_teamsrk  Z  sa  øè ø€ ô 1Ð1BÓC€NØ(,€Oáà˜4ÐÒrÐ$5×$=Ñ$=ÀTÐ$IÒrÐN_×NgÑNgÐkrÑNrð 	ð
 ×$Ñ$Ð0Ü'6Ø)×1Ñ1Ø+Ø#5Ø$Ø"3ô(÷ "ˆKð Ð&ð *×BÑBÒHÀbö#àØ—{‘{Ô&6×&@Ñ&@×&FÑ&FÒFÈ1×K\ÑK\ÐKhð ×%Ó%ð#�ð #ñ
 'Ø&*�OàÐ"©<ÜØàÐ`Ðar×a|Ña|Ð`}Ð~ðôð ð Ð"ä!-¬n¸]Ó.KÓ!L×!VÑ!VØ$ t¨_Ð&=Ð>Ø*¨DÐ1ð "Wó "
÷ 
ˆ	ñ Ü˜	“?Ð"ð "ö
àØ×&Ò&¬3Ó.lÐTX×TkÑTkÔ.lÔ+lò ò
ð 	
ñ
 
ä ,¬^¸MÓ-JÓ K× UÑ UØ*¨DÐ1ð !Vó !
÷ 
ˆð
 !ö
àØ×&Ò&¬3Ó.lÐTX×TkÑTkÔ.lÔ+lò ò
ð 	
ô œ,¤~°mÓ'DÓE×OÑOÐYnÐptÐXuÐOÓv×vÓwÐwðe"ûò#ð$
úò
ð
úò
ð wúsn   ƒAHÁ!HÁ"HÁ:AHÃ AHÄHÄHÄ,3HÅ.HÆHÆHÆ3HÇ	1HÇ:HÇ;	HÈHÈHÈHz
/team/listc           
   ƒ   óô  K  — ddl m}m}m} |€'t	        ddt
        j                  j                  i¬«      ‚t        |||||¬«      ƒ d{  –—† }|D �cg c]  }|j                  ‘Œ }	}t        ||	|¬«      ƒ d{  –—† }
g }|D ]œ  }g }|
D ]-  }|j                  |j                  k(  sŒ|j                  |«       Œ/ t        t        |«      j                  d	|j                  i¬
«      ƒ d{  –—† «      }	 |j                  t        di |j!                  «       ¤||dœ¤Ž«       Œž |j)                  d„ ¬«       |�Z|t*        j,                  j                  k(  r|D �cg c]  }|j.                  �Œ|‘Œ }}|S |D �cg c]  }|j.                  |k(  sŒ|‘Œ }}|S 7 �ŒHc c}w 7 �Œ!7 Œ´# t"        $ rD}d|j                  › d|j!                  «       › d|› d�}t%        j&                  |«       Y d}~�Œed}~ww xY wc c}w c c}w ­w)a¬  
    ```
    curl --location --request GET 'http://0.0.0.0:4000/team/list'         --header 'Authorization: Bearer sk-1234'
    ```

    Parameters:
    - user_id: str - Optional. If passed will only return teams that the user_id is a member of.
    - organization_id: str - Optional. If passed will only return teams that belong to the organization_id. Pass 'default_organization' to get all teams without organization_id.
    r   r  NrÅ  r  rS  )rî   r¯   r$  rI  rJ  r   r•   r�  )r¸  rO  z!Invalid team object for team_id: z. team_object=z.
            Error: z
            c                 ó$   — t        | dd«      xs dS )NrÈ   rA  )r¦  )Úxs    r�   ú<lambda>zlist_team.<locals>.<lambda>ê  s   € ¬'°!°\À2Ó*FÒ*LÈ"€ rœ   )rb  r›   )rL  r$  rJ  rI  r   r"   r�  r¢   rk  r•   r»  r”  r©   r>  r“  r?   r¹   rC  r   r–  Úsortr8   ÚDEFAULT_ORGANIZATIONrÛ   )r  r¯   rÛ   rî   r$  rJ  rI  Úfiltered_responserÐ  Ú	_team_idsr¹  Úreturned_responsesÚ_team_membershipsrº  rO  rv  Úteam_exceptions                    r�   Ú	list_teamrw  ¨  s.  è ø€ ÷$ñ ð ÐÜØØÔ.×EÑE×KÑKÐLô
ð 	
ô
 &AØ+ØØ#Ø-Ø+ô&÷  Ðð 2CÖC¨˜Ÿ›ÐC€IÐCÜ7¸ÀyÐZaÔb×b€Kà79ÐØ!ò ˆØ:<ÐØò 	-ˆBØ�z‰z˜TŸ\™\Ó)Ø!×(Ñ(¨Õ,ð	-ô
 œj¨Ó7×AÑAÈÐTX×T`ÑT`ÐHaÐAÓb×bÓcˆð	Ø×%Ñ%Ü&ñ Ø—o‘oÓ'ðà%6Øóõðð0 ×ÑÑ LÐÔMàÐ"ØÔ<×QÑQ×WÑWÒWØ3EÖ!f¨4È×I]ÑI]ÑIe¢$Ð!fÐÐ!fð Ðð 4FÖ!q¨4È×I]ÑI]ÐapÓIp¢$Ð!qÐÐ!qàÐðY ûò DØbùð cùô ò 	Ø!BÀ4Ç<Á<À.ÐP^Ð_c×_nÑ_nÓ_pÐ^qð rØ�3ð ðˆNô !×*Ñ*¨>Ô:Ýûð	üò "gùâ!qùs—   ‚AG8Á	FÁ
G8ÁFÁ%G8Á8FÁ9+G8Â%AG8Ã'F
Ã(G8Ã1-FÄ8G8ÅG.Å(G.Å,G8Å4G3Æ	G3ÆG8ÆG8ÆG8Æ	G+Æ'9G&Ç G8Ç&G+Ç+G8c              ƒ   ó  K  — 	 |dz
  |z  }t        | «      j                  «       ƒ d{  –—† }t        | «      j                  ||ddi¬«      ƒ d{  –—† }||fS 7 Œ/7 Œ
# t        $ r$}t	        j
                  d|«       g dfcY d}~S d}~ww xY w­w)a5  
    Get paginated list of teams from team table

    Parameters:
        prisma_client: PrismaClient - The database client
        page_size: int - Number of teams per page
        page: int - Page number (1-based)

    Returns:
        Tuple[List[LiteLLM_TeamTable], int] - (list of teams, total count)
    rÈ  NrÈ   rN  )rù   rø   rú   z0[Non-Blocking] Error getting paginated teams: %sr   )r'  rO  r“  rC  r   r–  )r$  rP  rO  rù   rZ  r¼  rv  s          r�   Úget_paginated_teamsry  õ  s£   è ø€ ð à˜a‘x 9Ñ,ˆä#+¨MÓ#:×#@Ñ#@Ó#B×Bˆô & mÓ4×>Ñ>ØØØ Ð'ð ?ó 
÷ 
ˆð
 �kÐ!Ð!ð Cøð
ùô ò Ü×&Ñ&Ð'YÐ[\Ô]Ø�1ˆu�ûðüsV   ‚B„$A ¨A©&A ÁAÁA ÁBÁA ÁA Á	B	Á%BÁ>B	Á?BÂB	Â	Bz/team/filter/uiéÈ   rÑ  )rþ  rÿ  Úinclude_in_schemaÚ	responsesz$Team alias in the request parametersé2   zNumber of items per pagec              ƒ   ó  K  — ddl m} |€t        dddi¬«      ‚	 |dz
  |z  }i }| r| d	d
œ|d<   |r|d	d
œ|d<   t        |«      j	                  |||ddi¬«      ƒ d{  –—† }|sg S |S 7 Œ
# t
        $ r}	t        dd|	› �¬«      ‚d}	~	ww xY w­w)a  
    [PROXY-ADMIN ONLY] Filter teams based on partial match of team_id or team_alias with pagination.

    Args:
        user_id (Optional[str]): Partial user ID to search for
        user_email (Optional[str]): Partial email to search for
        page (int): Page number for pagination (starts at 1)
        page_size (int): Number of items per page (max 100)
        user_api_key_dict (UserAPIKeyAuth): User authentication information

    Returns:
        List[LiteLLM_SpendLogs]: Paginated list of matching user records
    r   r&  Nr  r  r  rS  rÈ  r,  r(  r•   rÈ   r�  r�  rU  zError searching teams: )rL  r$  r   r'  r“  rC  )
r•   rÈ   rO  rP  rî   r$  rù   r.  r¼  rv  s
             r�   Úui_view_teamsr    sÜ   è ø€ õ: 9àÐÜ¨°WÐ>OÐ4PÔQÐQð!Sà˜a‘x 9Ñ,ˆð 79Ðáà#Ø%ñ+Ð˜YÑ'ñ
 à&Ø%ñ.Ð˜\Ñ*ô & mÓ4×>Ñ>Ø"ØØØ Ð(ð	 ?ó 
÷ 
ˆñ ØˆIàˆð
ùô ò SÜ¨Ð6MÈaÈSÐ4QÔRÐRûðSüsG   ‚B
›AA) ÁA'ÁA) Á$B
Á%A) Á&B
Á'A) Á)	BÁ2BÂBÂB
Ú
new_modelsc                 ó¼   — | j                   }|�*t        |«      dk(  rt        j                  j                  g}n| j                   }t        t        ||z   «      «      }|S )z8
    Add new models to a team's allowed model list.
    r   )r�   r–  r9   rë  r¢   r§  r¡  )rP  r€  Úcurrent_modelsÚupdated_modelss       r�   Úadd_new_models_to_teamr„  ]  sV   € ð —_‘_€NØÐ!¤c¨.Ó&9¸QÒ&>Ü+×<Ñ<×BÑBÐC‰à!Ÿ™ˆÜ ¤ ^°jÑ%@Ó!AÓB€NØÐrœ   z/team/model/addc              ƒ   ó†  K  — ddl m}m}m} |€t	        dddi¬«      ‚t        |«      j                  d| j                  i¬	«      ƒ d{  –—† }|€t	        d
dd| j                  › �i¬«      ‚t        j                  |j                  «       «      }|j                  t        j                  j                  k7  r1t        ||¬«      s$t!        ||¬«      ƒ d{  –—† st	        dddi¬«      ‚t#        | j$                  «      }|j&                  j)                  d|| j                  «      ƒ d{  –—†  t        |«      j+                  d| j                  idt-        j.                  t0        j2                  «      iddi¬«      ƒ d{  –—† }	|	€t	        d
dd| j                  › �i¬«      ‚t5        |	||¬«      ƒ d{  –—†  |	S 7 �Œn7 Œæ7 Œ•7 ŒA7 Œ­w)a
  
    Add models to a team's allowed model list. Only proxy admin or team admin can add models.

    Parameters:
    - team_id: str - Required. The team to add models to
    - models: List[str] - Required. List of models to add to the team

    Example Request:
    ```
    curl --location 'http://0.0.0.0:4000/team/model/add'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "team_id": "team-1234",
        "models": ["gpt-4", "claude-2"]
    }'
    ```
    r   r  Nr  r  r  rS  r•   r�  r‹  r—  rR  rö  ú5Only proxy admin or team admin can modify team modelsa  UPDATE "LiteLLM_TeamTable" SET models = (  SELECT ARRAY(SELECT DISTINCT unnest(    CASE WHEN cardinality(COALESCE(models, ARRAY[]::text[])) = 0          THEN ARRAY['all-proxy-models']::text[]          ELSE models     END || $1::text[]  ))) WHERE team_id = $2rB  rU  Tr›  rN  )rL  r$  rJ  rI  r   r'  r  r•   r,   rM  r¹   rV  r0   rW  r¢   r\   r[   r§  r�   r[  r  r  r   r_  r   r`  rO  )
rl  r  rî   r$  rJ  rI  rH  rP  Úmodels_to_addrý  s
             r�   Úteam_model_addrˆ  j  sç  è ø€ ÷:ñ ð ÐÜ¨°WÐ>OÐ4PÔQÐQô % ]Ó3×?Ñ?ÀyÐRV×R^ÑR^ÐF_Ð?Ó`×`€HàÐÜØØÐ>¸t¿|¹|¸nÐMÐNô
ð 	
ô
 (×6Ñ6°x×7JÑ7JÓ7LÓM€Hð 	×#Ñ#Ô'7×'CÑ'C×'IÑ'IÒIÜ#Ð6GÐRZÕ[Ü1ÐDUÐ`hÔi×iÐiäØØÐTÐUô
ð 	
ô   §¡Ó,€MØ
×
Ñ
×
&Ñ
&ð		ð 	Ø�‰ó÷ ð ô( !)¨Ó 7× >Ñ >Ø˜$Ÿ,™,Ð'ØœHŸL™L¬¯©Ó6Ð7Ø$ dÐ+ð !?ó !÷ €Lð
 ÐÜØØÐ>¸t¿|¹|¸nÐMÐNô
ð 	
ô
 ØØ-Ø+ô÷ ð ð Ðð aùð jøðøð(øðús]   ‚AGÁF6Á	B	GÃF9ÃAGÄ%F;Ä&AGÅ;F=Å<3GÆ/F?Æ0GÆ9GÆ;GÆ=GÆ?Gz/team/model/deletec              ƒ   ó  K  — ddl m}m}m} |€t	        dddi¬«      ‚t        |«      j                  d| j                  i¬	«      ƒ d{  –—† }|€t	        d
dd| j                  › �i¬«      ‚t        j                  |j                  «       «      }|j                  t        j                  j                  k7  r1t        ||¬«      s$t!        ||¬«      ƒ d{  –—† st	        dddi¬«      ‚|j"                  xs g }|D �	cg c]  }	|	| j"                  vsŒ|	‘Œ }
}	t        |«      j%                  d| j                  id|
iddi¬«      ƒ d{  –—† }|€t	        d
dd| j                  › �i¬«      ‚t'        |||¬«      ƒ d{  –—†  |S 7 �Œ77 Œ¯c c}	w 7 ŒD7 Œ­w)a  
    Remove models from a team's allowed model list. Only proxy admin or team admin can remove models.

    Parameters:
    - team_id: str - Required. The team to remove models from
    - models: List[str] - Required. List of models to remove from the team

    Example Request:
    ```
    curl --location 'http://0.0.0.0:4000/team/model/delete'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "team_id": "team-1234",
        "models": ["gpt-4"]
    }'
    ```
    r   r  Nr  r  r  rS  r•   r�  r‹  r—  rR  rö  r†  r�   rU  Tr›  rN  )rL  r$  rJ  rI  r   r'  r  r•   r,   rM  r¹   rV  r0   rW  r¢   r\   r[   r�   r  rO  )rl  r  rî   r$  rJ  rI  rH  rP  r‚  r™  rƒ  rý  s               r�   Úteam_model_deleterŠ  Ó  sÊ  è ø€ ÷:ñ ð ÐÜ¨°WÐ>OÐ4PÔQÐQô % ]Ó3×?Ñ?ÀyÐRV×R^ÑR^ÐF_Ð?Ó`×`€HàÐÜØØÐ>¸t¿|¹|¸nÐMÐNô
ð 	
ô
 (×6Ñ6°x×7JÑ7JÓ7LÓM€Hð 	×#Ñ#Ô'7×'CÑ'C×'IÑ'IÒIÜ#Ð6GÐRZÕ[Ü1ÐDUÐ`hÔi×iÐiäØØÐTÐUô
ð 	
ð ,4¯?©?Ò+@¸b€Nð )7ÖO 1¸!À4Ç;Á;Ò:NšQÐO€NÐOô !)¨Ó 7× >Ñ >Ø˜$Ÿ,™,Ð'Ø˜Ð'Ø$ dÐ+ð !?ó !÷ €Lð
 ÐÜØØÐ>¸t¿|¹|¸nÐMÐNô
ð 	
ô
 ØØ-Ø+ô÷ ð ð Ðð[ aùð júò Pðøðús[   ‚AFÁE?Á	B	FÃFÃ'FÃ:FÄFÄ2FÅF	Å3FÅ8FÅ9FÆFÆFÆFz/team/permissions_listc           	   ƒ   óR  K  — ddl m}m}m} |€t	        dddi¬«      ‚t        | ||d|dd	¬
«      ƒ d{  –—† }t        j                  |j                  «       «      }t        |d«      rmt        |«      sbt        ||¬«      sUt        ||¬«      ƒ d{  –—† s@t        |j                  |¬«      s)t	        dddj                  d|j                  «      i¬«      ‚|j                   €t#        j$                  «       |_        t'        | |j                   t#        j(                  «       ¬«      S 7 Œï7 Œ•­w)z4
    Get the team member permissions for a team
    r   r  Nr  r  r  rS  FTr5  rV  rR  r¯  rö  rÌ  rÍ  )r•   r  Úall_available_permissions)rL  r$  rJ  rI  r   rP   r,   rM  r¹   r¨  ra   r\   r[   r°  r•   rÏ  r  rm   Údefault_team_member_permissionsr‡   Ú)get_all_available_team_member_permissions)r•   rî   r$  rJ  rI  rx  r;  s          r�   r  r  *  s=  è ø€ ÷ñ ð ÐÜ¨°WÐ>OÐ4PÔQÐQô &5ØØ#Ø-ØØ+ØØô&÷  Ðô !2× @Ñ @ÐAR×A]ÑA]ÓA_Ó `Ðô
 	Ð! ;Ô/Ü$Ð%6Ô7Ü#Ð6GÐRdÕeÜ1ÐDUÐ`rÔs×sÐsÜ"Ø&×.Ñ.Ø/õ
ô
 ØàÐe×lÑlØ&Ø&×.Ñ.óðô
ð 	
ð ×0Ñ0Ð8Ü4N×4nÑ4nÓ4pÐÔ1ä+ØØ 1× IÑ IÜ"<×"fÑ"fÓ"hôð ðK øð$ tús#   ‚1D'³D#´AD'ÂD%ÂBD'Ä%D'ú/team/permissions_updatec           	   ƒ   ó�  K  — ddl m}m}m} |€t	        dddi¬«      ‚t        | j                  ||d|dd	¬
«      ƒ d{  –—† }t        j                  |j                  «       «      }t        |d«      rr|j                  t        j                  j                  k7  rKt        ||¬«      s>t!        ||¬«      ƒ d{  –—† s)t	        dddj#                  d|j                  «      i¬«      ‚t%        |«      j'                  d| j                  id| j(                  i¬«      ƒ d{  –—† }|€t	        ddd| j                  › �i¬«      ‚|S 7 �Œ7 ŒŒ7 Œ)­w)z7
    Update the team member permissions for a team
    r   r  Nr  r  r  rS  FTr5  rV  rR  rö  rÌ  r�  r•   r  r’  r‹  r—  )rL  r$  rJ  rI  r   rP   r•   r,   rM  r¹   r¨  rV  r0   rW  r¢   r\   r[   rÏ  r'  r  r  )	rl  r  rî   r$  rJ  rI  rx  r;  rý  s	            r�   Úupdate_team_member_permissionsr‘  m  sm  è ø€ ÷ñ ð ÐÜ¨°WÐ>OÐ4PÔQÐQô &5Ø—‘Ø#Ø-ØØ+ØØô&÷  Ðô !2× @Ñ @ÐAR×A]ÑA]ÓA_Ó `Ðô
 	Ð! ;Ô/Ø×'Ñ'Ô+;×+GÑ+G×+MÑ+MÒMÜ#Ð6GÐRdÕeÜ1ÐDUÐ`rÔs×sÐsäØàÐe×lÑlØ.Ø&×.Ñ.óðô
ð 	
ô !)¨Ó 7× >Ñ >Ø˜$Ÿ,™,Ð'Ø'¨×)EÑ)EÐFð !?ó !÷ €Lð ÐÜØØÐ>¸t¿|¹|¸nÐMÐNô
ð 	
ð
 ÐðQ ùð$ tøðús5   ‚;E½D?¾A7EÂ5EÂ6A$EÄEÄ%EÅEÅEz/team/permissions_bulk_updatec              ƒ   ó4  K  — ddl m} |€t        dddi¬«      ‚|j                  t        j
                  j                  k7  rt        ddd	i¬«      ‚| j                  sd
ddœS | j                  s| j                  st        dddi¬«      ‚| j                  r| j                  rt        dddi¬«      ‚t        | j                  «      }| j                  r t        || j                  |«      ƒ d{  –—† }nt        ||«      ƒ d{  –—† }d|| j                  dœS 7 Œ)7 Œ­w)a  
    Append permissions to existing teams.

    Either pass team_ids to target specific teams, or set
    apply_to_all_teams=True to update every team. For each team,
    the provided permissions are merged with the team's existing
    permissions (duplicates are skipped).
    r   r&  Nr  r  r  rS  rö  z2Only proxy admins can bulk-update team permissionszNo permissions provided)rÄ  Úteams_updatedrÅ  z4Must provide team_ids or set apply_to_all_teams=truez4Cannot set both apply_to_all_teams=true and team_idsz%Team permissions updated successfully)rÄ  r“  Úpermissions_appended)rL  r$  r   rV  r0   rW  r¢   ÚpermissionsÚapply_to_all_teamsr±  r¡  Ú%_append_permissions_to_specific_teamsÚ _append_permissions_to_all_teams)rl  rî   r$  Úpermissions_to_addr“  s        r�   Ú#bulk_update_team_member_permissionsrš  ¯  s/  è ø€ õ& 9àÐÜ¨°WÐ>OÐ4PÔQÐQà×"Ñ"Ô&6×&BÑ&B×&HÑ&HÒHÜØØÐQÐRô
ð 	
ð
 ×Òà0Øñ
ð 	
ð
 ×"Ò"¨4¯=ª=ÜØØÐSÐTô
ð 	
ð
 ×Ò 4§=¢=ÜØØÐSÐTô
ð 	
ô
 !$ D×$4Ñ$4Ó 5Ðà‡}‚}ÜCÀMÐSW×S`ÑS`ÐbtÓu×u‰ä>¸}ÐN`Óa×aˆð ;Ø&Ø $× 0Ñ 0ñð ð	 vøàaús$   ‚C(DÃ*DÃ+DÃ?DÄ DÄDz)Sequence[prisma_models.LiteLLM_TeamTable]r™  c              ƒ   óˆ  K  — g }|D ]L  }t        |j                  xs g «      }||k  rŒ"t        ||z  «      }|j                  |j                  |f«       ŒN |r]| j
                  j                  «       }|D ]&  \  }}	|j                  j                  d|id|	i¬«       Œ( |j                  «       ƒ d{  –—†  t        |«      S 7 Œ­w)zSCompute merged permissions and batch-write updates. Returns count of teams updated.r•   r  r’  N)r¡  r  r  r”  r•   r[  Úbatch_r
  r  Úcommitr–  )
r$  r¼  r™  ÚupdatesrÐ  ÚexistingÚmergedÚbatcherr•   Úmerged_permss
             r�   Ú_compute_and_batch_updatesr£  í  sØ   è ø€ ð €GØò /ˆÜ�t×3Ñ3Ò9°rÓ:ˆØ Ò)ØÜ˜Ð#5Ñ5Ó6ˆØ�‰˜Ÿ™ fÐ-Õ.ð/ñ Ø&×)Ñ)×0Ñ0Ó2ˆØ%,ò 	Ñ!ˆG�\Ø×%Ñ%×,Ñ,Ø  'Ð*Ø/°Ð>ð -õ ð	ð
 �n‰nÓ×Ðäˆw‹<Ðð 	ús   ‚B.CÂ0C Â1Cc              ƒ   ó  K  — t        | «      j                  dd|ii¬«      ƒ d{  –—† }|D �ch c]  }|j                  ’Œ }}t        |«      |z
  }|rt	        dddt        |«      › �i¬«      ‚t        | ||«      ƒ d{  –—† S 7 Œ]c c}w 7 Œ­w)	z2Fetch specific teams by ID and append permissions.r•   r³  r�  Nr‹  r  zTeam(s) not found: rS  )r'  r“  r•   r¡  r   r  r£  )r$  r±  r™  r¼  rÐ  Ú	found_idsÚmissing_idss          r�   r—  r—    s©   è ø€ ô " -Ó0×:Ñ:Ø˜4 Ð*Ð+ð ;ó ÷ €Eð 27Ö7¨˜Ÿ›Ð7€IÐ7Ü˜X›¨Ñ2€KÙÜØØÐ2´6¸+Ó3FÐ2GÐHÐIô
ð 	
ô
 ,¨M¸5ÐBTÓU×UÐUðúò 8ð Vús,   ‚#B¥B¦B®BÁ=BÁ>B
Á?BÂBc              ƒ   ó  K  — d}d}d}	 |ddidœ}|�d|i|d<   d|d	<    t        | «      j                  di |¤Žƒ d{  –—† }|s	 |S |t        | ||«      ƒ d{  –—† z  }|d
   j                  }t	        |«      |k  r	 |S Œv7 ŒB7 Œ)­w)z0Paginated read + batched write across all teams.r   Nr  r•   rN  )rø   rú   rû   rÈ  rù   éÿÿÿÿr›   )r'  r“  r£  r•   r–  )r$  r™  r“  rû   Ú
BATCH_SIZEÚ	find_argsr¼  s          r�   r˜  r˜    sÆ   è ø€ à€MØ€FØ€Jà
àØ Ð'ñ(
ˆ	ð ÐØ#,¨fÐ"5ˆI�hÑØ !ˆI�fÑà7”h˜}Ó-×7Ñ7ÑD¸)ÑD×DˆáØð Ðð 	Ô9¸-ÈÐPbÓc×cÑcˆà�r‘×"Ñ"ˆäˆu‹:˜
Ò"ØàÐð+ ð Eøð
 dús!   ‚;B½B ¾BÁBÁ(BÂBc                 ó    — t        | d|i¬«      S )z{Single construction site for the `{"error": ...}` detail shape the
    /team/daily/activity endpoints have always returned.r  rS  rt  ©rT  rÄ  s     r�   Ú_daily_activity_errorr­  6  s   € ô  [¸'À7Ð9KÔLÐLrœ   c                   ót   — e Zd ZU ee   dz  ed<   ee   dz  ed<   eeeeef   f   ed<   eee   z  dz  ed<   y)Ú_TeamDailyActivityScopeNr±  Úexclude_team_idsÚteam_alias_metadataÚapi_key_filter)r–   r—   r˜   r§  r¡   rš   râ   r»   r›   rœ   r�   r¯  r¯  <  sL   … Ø�3‰i˜$ÑÓØ˜3‘i $Ñ&Ó&Ø˜c 4¨¨V¨Ñ#4Ð4Ñ5Ó5Ø˜$˜s™)‘O dÑ*Ô*rœ   r¯  r°  ra  c           	   ƒ   ó  K  — | r| j                  d«      nd}d}|r|r|j                  d«      nd}t        |«      s€t        |j                  |d||j                  |d¬«      ƒ d{  –—† }	|	€t        dd|j                  › d�¬	«      ‚|€|	j                  }n&|D ]!  }
|
|	j                  vsŒt        dd
|
› d�¬	«      ‚ i }|rdt        |«      i|d<   t        |«      j                  |¬«      ƒ d{  –—† }|D �ci c]$  }|j                  dt        |j                  «      i“Œ& }}d}t        |«      s°|r®|r¬d}|D ]I  }t        j                  |j                  «       «      }t!        ||¬«      }t#        ||d¬«      }|rŒD|rŒGd} n |sZt%        |«      j                  d|j                  i¬«      ƒ d{  –—† }|D �cg c]  }|j&                  sŒ|j&                  ‘Œ }}|sdg}|}|€|�|}t)        ||||¬«      S 7 �Œ‘7 �Œc c}w 7 ŒQc c}w ­w)z×Resolve which teams the caller may see and whether results must be
    narrowed to their own API keys. Shared by the paginated and aggregated
    /team/daily/activity endpoints so both enforce identical permissions.ú,NFT)r¯   r$  rð  rI  r6  rJ  r8  r‹  zUser= z
 not foundr¬  zUser does not belong to Team= z'. Call `/user/info` to see user's teamsr³  r•   r�  rÈ   rR  ú/team/daily/activity)rî   rP  Ú
permissionr¯   rA  )r±  r°  r±  r²  )Úsplitra   rQ   r¯   r6  r­  r¼  r§  r'  r“  r•   r¦   rÈ   r,   rM  r¹   r\   r^   r>  r¶  r¯  )r±  r°  ra  rî   r$  rI  rJ  Úteam_ids_listÚexclude_team_ids_listr  r•   Úwhere_conditionÚteam_aliasesrB  r±  Úuser_api_keysÚhas_full_team_viewrÈ   rP  Úis_adminÚhas_permÚ	user_keysrb  Úfinal_api_key_filters                           r�   Ú"_resolve_team_daily_activity_scoperÂ  C  sZ  è ø€ ñ ,4�H—N‘N 3Ô'¸€MØ.2ÐáÙ?OÐ 0× 6Ñ 6°sÔ ;ÐUYÐäÐ 1Ô2Ü!0Ø%×-Ñ-Ø'Ø Ø1Ø.×?Ñ?Ø/Øô"
÷ 
ˆ	ð ÐÜ'°CÀ6ÐJ[×JcÑJcÐIdÐdnÐAoÔpÐpàÐ Ø%ŸO™O‰Mð )ò �Ø )§/¡/Ò1Ü/Ø$'Ø"@ÀÀ	ÐIpÐ qôð ðð /1€OÙØ&*¬D°Ó,?Ð%@ˆ˜	Ñ"Ü (¨Ó 7× AÑ AÈÐ AÓ X×X€LØ_kÖ!lÐZ[ !§)¡)¨l¼JÀqÇ|Á|Ó<TÐ-UÑ"UÐ!lÐÐ!lð '+€MÜÐ 1Ô2±}ÉØ!ÐØ&ò 
	ˆJÜ(×7Ñ7¸
×8MÑ8MÓ8OÓPˆHÜ*Ð=NÐYaÔbˆHÜ2Ø"3Ø!Ø1ôˆHò
 ¢Ø%*Ð"Ùð
	ñ "ä%/°Ó%>×%HÑ%HÐPYÐ[l×[tÑ[tÐOuÐ%HÓ%v×vˆIØ2;ÖI¨3¸s¿y»y˜SŸY›YÐIˆMÐIá Ø!# �ð 4;ÐØÐ#¨Ð(AØ,Ðä"ØØ.Ø/Ø+ô	ð ðK
ùð6 YûÚ!lð<  wúÚIùso   ‚A#HÁ%G6Á&AHÂ*AHÃ.G9Ã/HÃ7)G<Ä AHÅ;HÅ>1HÆ/HÆ0HÆ8HÇ
HÇHÇ9HÇ<HÈHrµ  )r   rþ  Ú
start_dateÚend_datec	              ƒ   ó6  K  — ddl m}	m}
m} |	€%t	        dt
        j                  j                  ¬«      ‚t        |||| |	||
¬«      ƒ d{  –—† }t        |	dd|j                  |j                  |j                  ||||j                  ||¬	«      ƒ d{  –—† S 7 ŒK7 Œ­w)
aø  
    Get daily activity for specific teams or all teams.

    Args:
        team_ids (Optional[str]): Comma-separated list of team IDs to filter by. If not provided, returns data for all teams.
        start_date (Optional[str]): Start date for the activity period (YYYY-MM-DD).
        end_date (Optional[str]): End date for the activity period (YYYY-MM-DD).
        model (Optional[str]): Filter by model name.
        api_key (Optional[str]): Filter by API key.
        page (int): Page number for pagination.
        page_size (int): Number of items per page.
        exclude_team_ids (Optional[str]): Comma-separated list of team IDs to exclude.
    Returns:
        SpendAnalyticsPaginatedResponse: Paginated response containing daily activity data.
    r   r  Nr  r¬  ©r±  r°  ra  rî   r$  rI  rJ  Úlitellm_dailyteamspendr•   )r$  r  Úentity_id_fieldÚ	entity_idÚentity_metadata_fieldÚexclude_entity_idsrÃ  rÄ  rÑ  ra  rO  rP  )rL  r$  rJ  rI  r­  r"   r�  r¢   rÂ  rd   r±  r±  r°  r²  )rî   r±  rÃ  rÄ  rÑ  ra  rO  rP  r°  r$  rJ  rI  Úscopes                r�   Úget_team_daily_activityrÍ  ¥  s¯   è ø€ ÷>ñ ð ÐÜ#°Ô=N×=eÑ=e×=kÑ=kÔlÐlä;ØØ)ØØ+Ø#Ø-Ø+ô÷ €Eô $Ø#Ø+Ø!Ø—.‘.Ø#×7Ñ7Ø ×1Ñ1ØØØØ×$Ñ$ØØô÷ ð ðøðús%   ‚ABÁ	BÁ
ABÂBÂBÂBrÅ  Ú_MAX_AGGREGATED_RANGE_DAYSc                 óJ  — | �|€y	 t        j                  | d«      j                  t        j                  ¬«      }t        j                  |d«      j                  t        j                  ¬«      }||k  ry||z
  j                  t        kD  r
dt        › d�S y# t
        $ r Y yw xY w)	zœThe aggregated endpoint has no pagination to bound its work, so malformed
    dates and ranges wider than the UI ever requests are rejected before querying.Nz&Please provide start_date and end_datez%Y-%m-%d)Útzinfoz6start_date and end_date must be valid YYYY-MM-DD datesz'end_date must be on or after start_datezDate range must be at most z days)r   ÚstrptimerE  r   r`  r·  ÚdaysrÎ  )rÃ  rÄ  Úparsed_startÚ
parsed_ends       r�   Ú_aggregated_date_range_errorrÕ  ê  s±   € ð Ð˜XÐ-Ø7ðHÜ&×/Ñ/°
¸JÓG×OÑOÔW_×WcÑWcÐOÓdˆÜ$×-Ñ-¨h¸
ÓC×KÑKÔS[×S_ÑS_ÐKÓ`ˆ
ð �LÒ Ø8Ø�\Ñ!×'Ñ'Ô*DÒDØ,Ô-GÐ,HÈÐNÐNØøô ò HÙGðHús   ‡A(B Â	B"Â!B"z/team/daily/activity/aggregatedr   c              ƒ   ól  K  — ddl m}m}	m}
 |€%t	        dt
        j                  j                  ¬«      ‚t        ||«      }|�t	        d|¬«      ‚t        |||| ||
|	¬«      ƒ d{  –—† }t        |dd	|j                  |j                  ||||j                  |j                  |d
¬«      ƒ d{  –—† S 7 ŒK7 Œ­w)a  
    Aggregated daily activity for teams without pagination, including per-team breakdown.

    One SQL GROUPING SETS pass returns every day in the range regardless of row
    volume, so callers never reassemble pages. Same response shape as the
    paginated endpoint with page metadata pinned to a single page.

    Args:
        team_ids (Optional[str]): Comma-separated list of team IDs to filter by. If not provided, returns data for all teams.
        start_date (Optional[str]): Start date for the activity period (YYYY-MM-DD).
        end_date (Optional[str]): End date for the activity period (YYYY-MM-DD).
        model (Optional[str]): Filter by model name.
        api_key (Optional[str]): Filter by API key.
        exclude_team_ids (Optional[str]): Comma-separated list of team IDs to exclude.
        timezone (Optional[int]): Timezone offset in minutes from UTC, matching JavaScript's Date.getTimezoneOffset() convention.
    Returns:
        SpendAnalyticsPaginatedResponse: Response containing all daily activity data for the range.
    r   r  Nr  r¬  rÅ  rÆ  rÇ  r•   T)r$  r  rÈ  rÉ  rÊ  rÃ  rÄ  rÑ  ra  rË  Útimezone_offset_minutesÚinclude_entity_breakdown)rL  r$  rJ  rI  r­  r"   r�  r¢   rÕ  rÂ  rY   r±  r±  r²  r°  )rî   r±  rÃ  rÄ  rÑ  ra  r°  r   r$  rJ  rI  Úrange_errorrÌ  s                r�   Ú"get_team_daily_activity_aggregatedrÚ  û  sÏ   è ø€ ÷Bñ ð ÐÜ#°Ô=N×=eÑ=e×=kÑ=kÔlÐlä5°jÀ(ÓK€KØÐÜ#°¸[ÔIÐIä;ØØ)ØØ+Ø#Ø-Ø+ô÷ €Eô /Ø#Ø+Ø!Ø—.‘.Ø#×7Ñ7ØØØØ×$Ñ$Ø ×1Ñ1Ø (Ø!%ô÷ ð ðøðús%   ‚A"B4Á$B0Á%AB4Â+B2Â,B4Â2B4)rô   rì   r£   rì   )r)  r�   r£   r  r¥   )F)Nr"  NNN)r  rÈ  )NNNNNrÈ  r  N)NNNNNNN(X  r  r]  rÔ   rM  rû  Úcollections.abcr   r   r   r   r   r   Útypesr   Útypingr	   r
   r   r   r   r   r   r   Úfastapir   r   r   r   r   r   Úpydanticr   r   Útyping_extensionsr   r   r¤  Úlitellm._loggingr   Úlitellm._uuidr   Úlitellm.integrations.prometheusr   Ú*litellm.litellm_core_utils.safe_json_dumpsr   ru  r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rG   Úlitellm.proxy.auth.auth_checksrH   rI   rJ   rK   rL   rM   rN   rO   rP   rQ   rR   Úlitellm.proxy.auth.auth_utilsrS   rT   Ú$litellm.proxy.auth.user_api_key_authrU   Ú)litellm.proxy.common_utils.callback_utilsrV   Ú+litellm.proxy.common_utils.json_merge_patchrW   Ú-litellm.proxy.common_utils.user_api_key_cacherX   Ú8litellm.proxy.management_endpoints.common_daily_activityrY   Ú/litellm.proxy.management_endpoints.common_utilsrZ   r[   r\   r]   r^   r_   r`   ra   rb   Ú9litellm.proxy.management_endpoints.organization_endpointsrc   Ú;litellm.proxy.management_endpoints.tag_management_endpointsrd   Ú7litellm.proxy.management_helpers.access_group_team_syncre   rf   rg   rh   ri   Ú8litellm.proxy.management_helpers.object_permission_utilsrj   rk   rl   Ú>litellm.proxy.management_helpers.team_member_permission_checksrm   Ú9litellm.proxy.management_helpers.team_metadata_validationrn   ro   Ú&litellm.proxy.management_helpers.utilsrp   rq   rr   Úlitellm.proxy.utilsrs   rt   ru   Ú&litellm.repositories.budget_repositoryrv   Ú,litellm.repositories.organization_repositoryrw   Ú%litellm.repositories.prisma_protocolsrx   Ú'litellm.repositories.table_repositoriesry   rz   r{   r|   r}   Ú$litellm.repositories.team_repositoryr~   Ú$litellm.repositories.user_repositoryr   Ú2litellm.repositories.verification_token_repositoryr€   Úlitellm.routerr�   Ú>litellm.types.proxy.management_endpoints.common_daily_activityr‚   Ú7litellm.types.proxy.management_endpoints.team_endpointsrƒ   r„   r…   r†   r‡   rˆ   r‰   rŠ   r‹   rŒ   r�   rŽ   Úprismar�   r�   Úprisma_modelsr‘   rš   r’   r”   rŸ   r»   r¦   r§  r©   r«   rµ   r·   r½   rÀ   rÂ   rÆ   rÍ   rÐ   r×   ræ   rè   rì   rõ   r÷   rþ   r   r  r  r  r  r  r!  r#  r'  r+  r-  r/  r1  r3  r5  r7  r9  r<  r>  r¡   rG  rO  rZ  r\  r«  rÕ   r°  r»  r™   râ   rÔ  rà  rä  ræ  rí  rò  rã   rù  rý  Úpostrw  r|  r�  rˆ  r�  r�  r¬  Úpatchr²  rŸ  r   r¹  r»  rÊ  rÔ  rò  rß  rê  rí  rö  r\  r  rŸ  r  r  r  r  r  r(  r3  r<  r>  rC  r]  r^  rc  rn  rr  rp  r}  r‡  r�  rš  r¯  r¤  r¥  r¢  r¦  rÇ  rÊ  r   rÎ  rÒ  rÚ  ró  r{  ÚQueryrf  r  r  r  r  r  r!  r1  rì  r>  rE  rJ  r_  rk  rw  ry  r  r„  rˆ  rŠ  r  r‘  rš  r¡  r£  r—  r˜  r­  r¯  rÂ  rÍ  rÎ  rÕ  rÚ  r›   rœ   r�   ú<module>r     sý  ðò	ó Û Û Û ß -Ý .ß 'Ý "ß a× aÓ aã ß N× Nß )ß 1ã Ý 1Ý Ý <Ý A÷*÷ *÷ *÷ *÷ *÷ *÷ *÷ *÷ *÷ *õ *÷V÷ ÷ ñ ÷õ CÝ KÝ NÝ Iõ÷
÷ 
õ 
õõ÷õ ÷ñ õ
÷÷ñ ÷
 VÑ UÝ CÝ OÝ >÷õ õ @Ý ?õõ "õ÷÷ ÷ ó ñ ÝÝ.á“€ˆÓ á�\Ó"€
ô�iô ô�iô ð
�fð  ó ð�8˜JÑ'ð ¨D°Ñ,<ó ô)�ô )ð
˜>ð Ð.Hó ô6�Hô 6ô"�ô "ô
 B˜
 M°8Ô Aô6˜8ô 6ô
1˜(ô 1ô-Ð(¨(ô -ô>˜ô >ô*�*˜mÐ-AÀ>ÐSdÐfnô *ð&�~ð Ð*Eó ô$�8ô $ô
s�xô sôô!˜	¨õ !ô"˜¨%õ "ô
)�i uõ )ô+˜)ô +ô�9ô ôXÐ% xô Xô
h�hô hôbÐ% xô bð-Ð " Eó ñ /Ð0EÀtÐ/LÓMÐ �eÓ Mð/˜L¨4Ñ/ð /Ð4có /ôð9 |°dÑ':ð 9Ð?só 9ð/˜L¨4Ñ/ð /Ð4có /ð5˜\¨DÑ0ð 5Ð5eó 5ð7˜<¨$Ñ.ð 7Ð3jó 7ðAØ $Ñ&ðAàAóAð1˜l¨TÑ1ð 1Ð6gó 1ð6 L°4Ñ$7ð 6Ð<ró 6ð6 L°4Ñ$7ð 6Ð<ró 6ð<˜l¨TÑ1ð <Ð6mó <ð4˜Vð 4¨ó 4ðØðà'ðð $ðð 
ó	ð6Øðà%ðð 
ó÷:Pñ Pðf 3ð ¨6ó ð, ð ¸ð È4ó ð MQòØðØ+/°©9ðØ?BÀT¹zðà	Ð
 Ñ!óð2DØÐ!Ñ"ðDà
Ð,Ñ
,ðDð ˜D‘jðDð ˜D‘jð	Dð
 "& c¨3 h¡ðDð "& c¨3 h¡ðDð ðDð 
óDðN#
ØÐ!Ñ"ð#
à
Ð,Ñ
,ð#
ð ˜D‘jð#
ð ˜D‘jð	#
ð
 ð#
ð 
ó#
ðLØÐ!Ñ"ðà(ðð Ð,Ñ
,ðð 
ó	ðDØÐ!Ñ"ðà(ðð Ð,Ñ
,ðð 
ó	ð2dØ(ðdà
Ð,Ñ
,ðdð  ðdð 
ó	dðNE
Ø
Ð,Ñ
,ðE
à%ðE
ð  ðE
ð (ð	E
ð
 
óE
ðP"
Ø
ð"
à%ð"
ð $ d™lð"
ð 
ó	"
ðJUØ%ðUà˜c 6˜kÑ*ðUð 
óUð ‡‚ØØ
Ð	ÙÐ+Ó,Ð-Ø$ð	 ó ð ñ )0Ð0AÓ(BÙ%+Øð tô&ñ	q+Ø
ðq+àðq+ð &ðq+ð ˜d™
ò	q+ó óðq+ðh.Ø(ð.àð.ð ð.ð ˜d™
ð	.ð
 &ð.ð "ð.ð 
ó.ðbØ
ðà�D‰jðð  ðð &ð	ð
 "ðð 	ˆ4�ZóðD$Ø
ð$à6ð$ð  ð$ð 
ô	$ðX 04ò4Øð4à$ð4ð ˜‘ð4ð  ð	4ð
 &¨Ñ,ð4ð /ô4ðv !ò	dØ
ðdà6ðdð ðdð ð	dð
 
ôdðN ‡‚ˆ^Ð#4Ð"5ÁWÐM^ÓE_ÐD`€ÓaØñ )0Ð0AÓ(BÙ%+Øð tô&ñ	O+Ø
ðO+àðO+ð &ðO+ð ˜d™
ò	O+ó ó bñO+ðd ‡‚ØØ
Ð	ÙÐ+Ó,Ð-Ø$ð	 ó ð  	òD+ØðD+à
ðD+ð ðD+ð ! ±Ð9JÓ1KÐ!KÑLð	D+ð
 "Øˆd‰
Ùð xô	
ð	ñòD+óñD+ðNFÐ0ð F¸dð FÀtô Fð*°Tð ÐNbð Ðgkô ð0Ø�T˜&‘\Ñ!ðàôð GØ $Ñ&ðGà
ðGð ôGð.3
Ø
ð3
à(ô3
ðlMØ%ðMà)ðMð ðMð 
ô	Mðl  $òH3Ø
ðH3à)ðH3ð  ðH3ð &ð	H3ð
 "ðH3ð 	˜ÑðH3ñ ˆ4Ð!Ñ" DÐ)?Ñ$@Ð@ÑAôH3ðV Vð ¸HÐEVÑ<Wð Ð\bô ð@ Fð Ð@Qð ÐVZô ðØ
ðà)ðð Ð)Ñ*ðð 
ô	ð&5AØ
ð5Aà)ð5Að  ð5Að &ð	5Að
 "ð5Añ Ð,¨dÐ3DÑ.EÀtÐLbÑGcÐcÑdô5AðpaÐ$5ð a¸$ô aðWØ�fÑðWàðWñ ˆs�^ôWð.2Ø�fÑð2á'¨™nð2ñ ! ‘~ð2ñ ˆs�^ô	2ð( )+Ñ  Ó *ð!Ø�fÑð!á  ‘~ð!ð &ð!ð 
ô	!ðH
 (¨6Ñ"2ð 
°sô 
ð*BØð*BàÐ-Ñ.ð*Bñ ! ‘~ð*Bð ˜VÑ$ð	*Bð
 ˜FÑ#ð*Bð &ð*Bð "ð*Bð 
ô*BðZeØðeàðeð ôeðP ‡‚ØØ
Ð	ÙÐ+Ó,Ð-Ø(ð	 ó ð ñ )0Ð0AÓ(BñCØ
ðCà%òCó óñCðL Fð Ð2Ið Èdô ð2Ø(ð2à
!ð2ñ ‰5�˜�Ñ˜t F™|Ð+Ñ,ô2ð" ‡‚ØØ
Ð	ÙÐ+Ó,Ð-ð ó ð
 ñ )0Ð0AÓ(Bñ\Ø
!ð\à%ò\ó óñ\ð@ 'ØØØ(Ø&ñ&Ñ ˜Uó ð	Ð%<ð 	ÀÀcÈ6ÀkÑARô 	ð ‡‚ØØ
Ð	ÙÐ+Ó,Ð-Ø+ð	 ó ð ñ )0Ð0AÓ(BñTØ
!ðTàðTð &òTó óñTðn
o¨Cð 
oÀNð 
oÐW[ô 
oð@¨#ð @¸ð @Àô @ð
Øðà&ðð ôð8 ‡‚Ø2Ø
Ð	ÙÐ+Ó,Ð.ð ó ð
 ð@Øð@àð@ð ð@ð ! ±Ð9JÓ1KÐ!KÑLò	@ó óñ@ðF$Ø�&‰\ð$à#ð$ð 
Ð
Ñô$ðN ‡‚ØØ
Ð	ÙÐ+Ó,Ð-Ø,ð	 ó ð ñ )0Ð0AÓ(BñH
Ø
"ðH
à%òH
ó óñH
ðV ‡‚ˆ^Ð#4Ð"5ÁWÐM^ÓE_ÐD`€ÓaØñ )0Ð0AÓ(BÙ%+Øð tô&ñ	DØ
ðDàðDð &ðDð ˜d™
ò	Dó ó bñDðNu°8¸C±=ð uÐQ]ð uÐbfô uð,M°h¸s±mð MÈð MÐ[_õ MñÙ
=ðà'ðð $ðð 
õ	ð&ØÐ%Ñ&ðà'ðð $ðð 
õ	ð* &*ò-ØÐ!Ñ"ð-à%ð-ð ˜d™
ð-ð 
ˆ$ˆs�Fˆ{Ñ
Ñõ	-ñ`DØ�$�s˜F�{Ñ#Ñ$ðDàðDð 
õDð &*ò	ØÐ!Ñ"ðàðð &ðð ˜d™
ð	ð
 
õð$&°ñ &ÐM^õ &ñR%Øð%àñ%ð  ?ð%ð %õ	%ð Øðà�fÑðñ ˆ6�3ˆ;ÑõñBØ/ðà$õð< ‡‚‰LÐ 1Ð2Á'ÐJ[ÓB\ÐA]€Ó^Øð !�7—=’=¨Ñ;^Õ_Ø)˜GŸMšM°$ÑDgÐlmÕnÙ(/Ð0AÓ(Bñ	P
ØðP
àñP
ð �T‰zðP
ð &ó	P
ó ó _ñP
ðf ‡‚Ù Ø
Ð	ÙÐ+Ó,Ð-Ø)ð	 ó ð ñ )0Ð0AÓ(BñhØðhàðhð &óhó óñhðV ‡‚‰]Ð"3Ð!4ÁGÐL]ÓD^ÐC_€Ó`Øñ )0Ð0AÓ(Bñ2Ø
ð2àð2ð &ó2ó ó añ2ðj ‡‚‰_Ð$5Ð#6ÁgÐN_ÓF`ÐEa€ÓbØñ )0Ð0AÓ(Bñ,Ø
ð,àð,ð &ó,ó ó cñ,ð^ ‡‚ÙØ
Ð	ÙÐ+Ó,Ð.Ø-ð	 ó ò	Róñ	Rð ‡‚ÑÓñ )0Ð0AÓ(BØÐ)Ñ*ñ'(Øð'(à%ó'(ó ñ'(ðT(Øð(àð(ð (ð(ð $ð	(ð
 
ˆ#�Y�Ñõ(ðR Ø.5Ø*.Ø15Ø-1òRØðRà�4‰ZñRð �d‘
ðRð ˜4‘Zð	Rð
 �4‰ZñRð ñRð �$‰JñRð ,ñRð ˜C‘y 4Ñ'ðRð (¨$Ñ.ðRð $ dÑ*ðRð 
ˆ#ˆvˆ+Ñ˜ÑõRñj6Ø˜s™)ð6á8õ6ð, 15òØñàñð ˜S #˜X™¨Ñ-ðð 
ˆ,Ð*Ñ
*Ð-EÑ
EÑFõ	ðBnØðnà�JÑðnð 
ˆ#ˆsˆ(�^õnð2B&Ø%ðB&à�4‰ZðB&ð ˜4‘ZðB&ð  ð	B&ð
 (ðB&ð $ðB&ñ ˆ3�‰:�t˜C‘y 4Ñ'Ð'Ñ(õB&ðJ ‡‚ÙØ
Ð	Ø#ÙÐ+Ó,Ð-ñ	 ó ð ð (˜'Ÿ-š-°ÑBuÕvØ"/ '§-¢-ØÙOõ#ð (˜'Ÿ-š-°ÑBuÕvØ*˜WŸ]š]ØÙfõð '˜ŸšØñ Mõñ 	Ø�—’¡aÑ5QÑVWÕXØ"�W—]’]¨2Ñ;UÑZ[Ñ`cÕdØ'˜'Ÿ-š-ØÙTõð $�g—m’m©EÑ?]Õ^Ø&˜Ÿš¨tÑAdÕeÙ(/Ð0AÓ(Bñ=sØðsà�4‰Zðsð ˜4‘Zðsð �4‰Zñsð �d‘
ñsð �$‰Jñsð  $ØØˆ�ŠÙzô	
ð	ññ!sð, ñ-sð. ñ/sð0 �4‰Zñ1sð8 ñ9sð: �$‰Jð;sð< &ó=só óñsðlKxØ%ðKxà�4‰ZðKxð  ðKxð (ð	Kxð
 $ðKxð 
õKxð\ ‡‚‰LÐ 1Ð2Á'ÐJ[ÓB\ÐA]€Ó^Øð (˜'Ÿ-š-°ÑBuÕvØ"&Ù(/Ð0AÓ(Bñ	HØðHà�4‰ZðHð ˜4‘ZðHð &ó	Hó ó _ñHðZ ØòØñàñð ðñ ˆ4Ð!Ñ" CÐ'Ñ(õ	ðD ‡‚ÙØ
Ð	ÙÐ+Ó,Ð-Øá‰g�tÐ-Ñ.Ð/ðñ ó ð (˜'Ÿ-š-°ÑBeÕfØ*˜WŸ]š]°4ÑEkÕlØ�—’¡aÑ5QÑVWÕXØ"�W—]’]©2Ñ;UÑZ[Ñ`cÕdÙ(/Ð0AÓ(Bñ:SØ�4‰Zñ:Sà�d‘
ñ:Sð ñ:Sð ð	:Sð
 &ó:Sóñ:Sðz
Ð%6ñ 
ÀDÈÁIð 
ÐRVÐWZÑR[õ 
ð ‡‚ÙØ
Ð	ÙÐ+Ó,Ð-ð ó ð
 ñ )0Ð0AÓ(Bñ`Ø
ð`àð`ð &ó`ó óñ`ðF ‡‚ÙØ
Ð	ÙÐ+Ó,Ð-ð ó ð
 ñ )0Ð0AÓ(BñNØ
 ðNàðNð &óNó óñNðb ‡‚ÙØ
Ð	ÙÐ+Ó,Ð-ð ó ð
 à �7—=’=¨Ñ;^Õ_Ù(/Ð0AÓ(Bñ:Øð:à%ð:ð &ó:ó óñ:ðz ‡‚ÙØ
Ð	ÙÐ+Ó,Ð-ð ó ñ )0Ð0AÓ(Bñ:Ø
,ð:àð:ð &ð:ð ó	:óñ
:ðz ‡‚Ù#Ø
Ð	ÙÐ+Ó,Ð-Ø:ð	 ó ð ñ )0Ð0AÓ(Bñ4Ø
0ð4à%ó4ó óñ4ðnÙEñÙ[^ðàõð0VØðVØ+/°©9ñVÙJMðVàõVð&¸,ñ Ñ\_ð Ðdgõ ð<M¨#ð M¸ð MÀõ Mö+˜jõ +ð_à�D‰jñ_ð ˜D‘jñ_ð �4‰Zð	_ð
 &ð_ð  ð_ð (ð_ð $ð_ñ õ_ðD ‡‚ÙØ2Ø
Ð	ñ ó ð  Ø!ØØØØØØ#'ò:Ø  ±Ð9JÓ1KÐ!KÑLð:à�D‰jñ:ð �d‘
ñ:ð �D‰jñ	:ð
 �‰:ñ:ð �4‰Zñ:ð ñ:ð ñ:ð ˜D‘jó:óñ
:ñz %(Ñ ˜EÔ 'ñ¨S°4©Zñ À3ÈÁ:ð ÐRUÐX\ÑR\õ ð" ‡‚Ù%Ø2Ø
Ð	ñ ó ð  Ø!ØØØØ#'Øò@Ø  ±Ð9JÓ1KÐ!KÑLð@à�D‰jñ@ð �d‘
ñ@ð �D‰jñ	@ð
 �‰:ñ@ð �4‰Zñ@ð ˜D‘jñ@ð �D‰jó@óò
@rœ   