o
    ưi                     @   sd  d Z ddlmZmZ ddlZddlmZmZmZmZ ddl	Z	ddl
mZ ddlT ddlmZ ddlmZ dd	lmZmZ dd
lmZ ddlmZ e ZejddgeegddejddgeegddefddZejddgeegddejddgeegddefddZdedee fddZde dee! de ddfdd Z"ejd!dgdeegd"ejd#dgeegdeefded$e#fd%d&Z$ej%d'dgeege!d(ej%d)dgdeegd"ej&d*d+fd,e'fd-d.Z(ejd/dgeegdejd0dgdeegd"eefde)d$e#fd1d2Z*ejd3dgeegdejd4dgdeegd"eefde+d$e#fd5d6Z,ej%d7dgeegee! d(ej%d8dgdeegd"eefd9ed$e#fd:d;Z-ej%d<dgeeged(ej%d=dgdeegd"dddddd>d?deef	d@ee' dAee' dBee' dCee' dDee' dEe.dFe.dGee' d$e#fdHdIZ/dS )Jz}
CUSTOMER MANAGEMENT

All /customer management endpoints 

/customer/new   
/customer/info
/customer/update
/customer/delete
    )ListOptionalN)	APIRouterDependsHTTPExceptionRequest)verbose_proxy_logger)*)user_api_key_auth)get_daily_activity)_set_object_permission&handle_update_object_permission_common)handle_exception_on_proxy)SpendAnalyticsPaginatedResponsez/end_user/blockzCustomer ManagementF)tagsdependenciesinclude_in_schemaz/customer/block)r   r   datac              
      s   ddl m} z5g }|dur0| jD ]}|jjjd|i|ddddidd	I dH }|| qntd
ddidd|iW S  ty\ } zt	
dt|  td
dt|idd}~ww )a  
    [BETA] Reject calls with this end-user id

    Parameters:
    - user_ids (List[str], required): The unique `user_id`s for the users to block

        (any /chat/completion call with this user={end-user-id} param, will be rejected.)

        ```
        curl -X POST "http://0.0.0.0:8000/user/block"
        -H "Authorization: Bearer sk-1234"
        -d '{
        "user_ids": [<user_id>, ...]
        }'
        ```
    r   prisma_clientNuser_idT)r   blockedr   )createupdatewherer     errorzPostgres DB Not connectedstatus_codedetailblocked_userszAn error occurred - )litellm.proxy.proxy_serverr   user_idsdblitellm_endusertableZupsertappendr   	Exceptionr   r   str)r   r   recordsidrecorde r-   l/home/app/Keep/.python/lib/python3.10/site-packages/litellm/proxy/management_endpoints/customer_endpoints.py
block_user!   s0   


r/   z/end_user/unblockz/customer/unblockc                    s   zddl m  W n ty   tdddtjj idw t fddtj	D r.tj
d	u r6tdddidttj
trI| jD ]}tj
| q?ntd
ddiddtj
iS )z
    [BETA] Unblock calls with this user id

    Example
    ```
    curl -X POST "http://0.0.0.0:8000/user/unblock"
    -H "Authorization: Bearer sk-1234"
    -d '{
    "user_ids": [<user_id>, ...]
    }'
    ```
    r   _ENTERPRISE_BlockedUserList  r   z:Blocked user check was never set. This call has no effect.r   c                 3   s    | ]}t | V  qd S )N)
isinstance).0xr0   r-   r.   	<genexpr>|   s    zunblock_user.<locals>.<genexpr>Nr   zF`blocked_user_list` must be set as a list. Filepaths can't be updated.r!   )Z-enterprise.enterprise_hooks.blocked_user_listr1   ImportErrorr   CommonProxyErrorsZ!missing_enterprise_package_dockervalueanylitellm	callbacksZblocked_user_listr3   listr#   remove)r   r*   r-   r0   r.   unblock_userW   s<   



r?   returnc                 C   sT   t j }i }|D ]}|dkrq	t| |d}|dur|||< q	|r(t di |S dS )zE
    Return a new budget object if new budget params are passed.
    	budget_idNr-   )BudgetNewRequestmodel_fieldskeysgetattr)r   Zbudget_paramsZbudget_kv_pairs
field_namer9   r-   r-   r.   new_budget_request   s   
rG   non_default_valuesend_user_table_data_typedupdate_end_user_table_datac                    sL   d| v r"|dur|j nd}t| ||dI dH }|dur$||d< dS dS dS )a  
    Handle object permission updates for customer endpoints.

    Updates the update_end_user_table_data dict in place with the new object_permission_id.

    Args:
        non_default_values: Dictionary containing the update values including object_permission
        end_user_table_data_typed: Existing end user table data
        update_end_user_table_data: Dictionary to update with new object_permission_id
        prisma_client: Prisma database client
    object_permissionN)	data_jsonexisting_object_permission_idr   object_permission_id)rN   r   )rH   rI   rJ   r   rM   rN   r-   r-   r.   )_handle_customer_object_permission_update   s   rO   z/end_user/new)r   r   r   z/customer/newuser_api_key_dictc              
      sH  	 ddl m}m}m} |du rtddtjjidz| jdurF|du r.tddtj	jid| j|
 vrFtddd| jt|
 idi }t| }|durz|jjji |jd	d
|jp`||jpd|ddI dH }W n ty } z
tddt|idd}~ww |j|d< n
| jdur| j|d< | jd	d}	|	 D ]\}
}|
tj vr|||
< qt||dI dH }d|v rtd|d  |dd |jj j|d	d	ddI dH }| }|drdD ]
}|d |d q|W S  ty# } z"t!dt| dt|v rt"d| j dddddt#|d}~ww )aF  
    Allow creating a new Customer 


    Parameters:
    - user_id: str - The unique identifier for the user.
    - alias: Optional[str] - A human-friendly alias for the user.
    - blocked: bool - Flag to allow or disallow requests for this end-user. Default is False.
    - max_budget: Optional[float] - The maximum budget allocated to the user. Either 'max_budget' or 'budget_id' should be provided, not both.
    - budget_id: Optional[str] - The identifier for an existing budget allocated to the user. Either 'max_budget' or 'budget_id' should be provided, not both.
    - allowed_model_region: Optional[Union[Literal["eu"], Literal["us"]]] - Require all user requests to use models in this specific region.
    - default_model: Optional[str] - If no equivalent model in the allowed region, default all requests to this model.
    - metadata: Optional[dict] = Metadata for customer, store information for customer. Example metadata = {"data_training_opt_out": True}
    - budget_duration: Optional[str] - Budget is reset at the end of specified duration. If not set, budget is never reset. You can set duration as seconds ("30s"), minutes ("30m"), hours ("30h"), days ("30d").
    - tpm_limit: Optional[int] - [Not Implemented Yet] Specify tpm limit for a given customer (Tokens per minute)
    - rpm_limit: Optional[int] - [Not Implemented Yet] Specify rpm limit for a given customer (Requests per minute)
    - model_max_budget: Optional[dict] - [Not Implemented Yet] Specify max budget for a given model. Example: {"openai/gpt-4o-mini": {"max_budget": 100.0, "budget_duration": "1d"}}
    - max_parallel_requests: Optional[int] - [Not Implemented Yet] Specify max parallel requests for a given customer.
    - soft_budget: Optional[float] - [Not Implemented Yet] Get alerts when customer crosses given budget, doesn't block requests.
    - spend: Optional[float] - Specify initial spend for a given customer.
    - budget_reset_at: Optional[str] - Specify the date and time when the budget should be reset.
    - object_permission: Optional[LiteLLM_ObjectPermissionBase] - Customer-specific object permissions to control access to resources.
        Supported fields:
        * mcp_servers: List[str] - List of allowed MCP server IDs
        * mcp_access_groups: List[str] - List of MCP access group names
        * mcp_tool_permissions: Dict[str, List[str]] - Map of server ID to allowed tool names (e.g., {"server_1": ["tool_a", "tool_b"]})
        * vector_stores: List[str] - List of allowed vector store IDs
        * agents: List[str] - List of allowed agent IDs
        * agent_access_groups: List[str] - List of agent access group names
        Example: {"mcp_servers": ["server_1", "server_2"], "vector_stores": ["vector_store_1"], "agents": ["agent_1"]}
        IF null or {} then no object-level restrictions apply.
    
    
    - Allow specifying allowed regions 
    - Allow specifying default model

    Example curl:
    ```
    curl --location 'http://0.0.0.0:4000/customer/new'         --header 'Authorization: Bearer sk-1234'         --header 'Content-Type: application/json'         --data '{
            "user_id" : "ishaan-jaff-3",
            "allowed_region": "eu",
            "budget_id": "free_tier",
            "default_model": "azure/gpt-3.5-turbo-eu"
        }'

    # With object permissions
    curl -L -X POST 'http://localhost:4000/customer/new'         -H 'Authorization: Bearer sk-1234'         -H 'Content-Type: application/json'         -d '{
            "user_id": "user_1",
            "object_permission": {
              "mcp_servers": ["server_1"],
              "mcp_access_groups": ["public_group"],
              "vector_stores": ["vector_store_1"]
            }
          }'

        # return end-user object
    ```

    NOTE: This used to be called `/end_user/new`, we will still be maintaining compatibility for /end_user/XXX for these endpoints
    r   )litellm_proxy_admin_name
llm_routerr   Nr   r   r   i  zmDefault Model not on proxy. Configure via `/model/new` or config.yaml. Default_model={}, proxy_model_names={}T)Zexclude_unsetZ
created_byZ
updated_by)r   rA   Zexclude_none)rL   r   rK   zJobject_permission still in new_end_user_obj after _set_object_permission: litellm_budget_tablerK   r   includeZteamsZverification_tokensZorganizationsZusers	end_usersz\litellm.proxy.management_endpoints.customer_endpoints.new_end_user(): Exception occured - {}z3Unique constraint failed on the fields: (`user_id`)z(Customer already exists, passed user_id=z. Please pass a new user_id.bad_requestr2   r   messagetypecodeparam)$r"   rQ   rR   r   r   r8   db_not_connected_errorr9   Zdefault_modelZno_llm_routerZget_model_namesformatsetrG   r$   litellm_budgettabler   
model_dumpr   r'   r(   rA   dictitemsrB   rC   rD   r   r   warninggetpopr%   	exceptionProxyExceptionr   )r   rP   rQ   rR   r   Znew_end_user_objZ_new_budgetZbudget_recordr,   Z
_user_datakvZend_user_recordresponse_dictfieldr-   r-   r.   new_end_user   s   Q


	



rq   z/customer/info)r   r   Zresponse_modelz/end_user/infoz%End User ID in the request parameters)descriptionend_user_idc              
      s   zOddl m} |du rtddtjjid|jjjd| iddd	d
I dH }|du r6t	d
| dddd|jdd}|drNdD ]
}|d |d qC|W S  tyj } ztd
t| t|d}~ww )ae  
    Get information about an end-user. An `end_user` is a customer (external user) of the proxy.

    Parameters:
    - end_user_id (str, required): The unique identifier for the end-user

    Example curl:
    ```
    curl -X GET 'http://localhost:4000/customer/info?end_user_id=test-litellm-user-4'         -H 'Authorization: Bearer sk-1234'
    ```
    r   r   Nr   r   r   r   TrU   r   rX   #End User Id={} does not exist in db	not_found  rs   r\   rT   rK   rY   z]litellm.proxy.management_endpoints.customer_endpoints.end_user_info(): Exception occured - {})r"   r   r   r8   ra   r9   r$   r%   
find_firstrl   rb   re   ri   rj   r'   r   rk   r(   r   )rs   r   Z	user_inforo   rp   r,   r-   r-   r.   end_user_info  s@   

ry   z/customer/updatez/end_user/updatec              
      s  ddl m}m} z?|  }|du rtdi }| D ]\}}|dur0|g i dfvr0|||< q|jjjd| j	iddidI dH }|du rRt
d	| j	d
dddtdi | }	|	j}
i }i }| D ]$\}}|dkrs|||< qf|tj v r|||< qf|tj v r|||< qft||	||dI dH  |r|
du r|jjji ||j	p||j	p|dddidI dH }|j|d< n|jjjd|
ji|dI dH }td|  d|v rtd|d  |dd | j	durBt| j	dkrB| j	|d< td |jjjd| j	i|ddddI dH }|du rtd| j	 td|  | }|dr?dD ]}|d |d q3|W S td| j	  tyd } ztdt| t |d}~ww )a  
    Example curl 

    Parameters:
    - user_id: str
    - alias: Optional[str] = None  # human-friendly alias
    - blocked: bool = False  # allow/disallow requests for this end-user
    - max_budget: Optional[float] = None
    - budget_id: Optional[str] = None  # give either a budget_id or max_budget
    - allowed_model_region: Optional[AllowedModelRegion] = (
        None  # require all user requests to use models in this specific region
    )
    - default_model: Optional[str] = (
        None  # if no equivalent model in allowed region - default all requests to this model
    )
    - object_permission: Optional[LiteLLM_ObjectPermissionBase] - Customer-specific object permissions to control access to resources.
        Supported fields:
        * mcp_servers: List[str] - List of allowed MCP server IDs
        * mcp_access_groups: List[str] - List of MCP access group names
        * mcp_tool_permissions: Dict[str, List[str]] - Map of server ID to allowed tool names
        * vector_stores: List[str] - List of allowed vector store IDs
        * agents: List[str] - List of allowed agent IDs
        * agent_access_groups: List[str] - List of agent access group names
        Example: {"mcp_servers": ["server_1"], "vector_stores": ["vector_store_1"]}
        IF null or {} then no object-level restrictions apply.

    Example curl:
    ```
    curl --location 'http://0.0.0.0:4000/customer/update'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "user_id": "test-litellm-user-4",
        "budget_id": "paid_tier"
    }'

    # Updating object permissions
    curl -L -X POST 'http://localhost:4000/customer/update'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "user_id": "user_1",
        "object_permission": {
          "mcp_servers": ["server_3"],
          "vector_stores": ["vector_store_2", "vector_store_3"]
        }
      }'

    See below for all params
    ```
    r   )rQ   r   NNot connected to DB!r   rV   Trt   ru   rv   rw   r\   rA   )rH   rI   rJ   r   rS   rZ   rW   r   z$/customer/update: Received data = %srK   z7object_permission still in update_end_user_table_data: z,In update customer, user_id condition block.rU   )r   r   rX   zEFailed updating customer data. User ID does not exist passed user_id=8received response from updating prisma client. response=rY   &user_id is required, passed user_id = zDlitellm.proxy.proxy_server.update_end_user(): Exception occured - {}r-   )!r"   rQ   r   jsonr'   rg   r$   r%   rx   r   rl   rb   LiteLLM_EndUserTablere   rV   ZLiteLLM_BudgetTablerC   rD   rO   rd   r   rA   r   r   debugrh   ri   rj   len
ValueErrorrk   r(   r   )r   rP   rQ   r   rL   rH   rm   rn   Zend_user_table_datarI   Zend_user_budget_tableZbudget_table_datarJ   Zbudget_table_data_recordresponsero   rp   r,   r-   r-   r.   update_end_user  s   C









r   z/customer/deletez/end_user/deletec              
      s<  ddl m} z||du rtdtd|  | jdur|t| jtr|t| jdkr||j	j
jdd| jiidI dH }d	d
 |D   fdd| jD }|rYtdd|dddd|j	j
jdd| jiidI dH }td|  |dt| j dW S td| j  ty } ztdt| t|d}~ww )a  
    Delete multiple end-users.

    Parameters:
    - user_ids (List[str], required): The unique `user_id`s for the users to delete

    Example curl:
    ```
    curl --location 'http://0.0.0.0:4000/customer/delete'         --header 'Authorization: Bearer sk-1234'         --header 'Content-Type: application/json'         --data '{
            "user_ids" :["ishaan-jaff-5"]
    }'

    See below for all params 
    ```
    r   r   Nrz   z$/customer/delete: Received data = %sr   inr   c                 S   s   h | ]}|j qS r-   )r   )r4   userr-   r-   r.   	<setcomp>  s    z"delete_end_user.<locals>.<setcomp>c                    s   g | ]}| vr|qS r-   r-   )r4   r   Zexisting_user_idsr-   r.   
<listcomp>  s    z#delete_end_user.<locals>.<listcomp>z$End User Id(s)={} do not exist in dbz, rv   rw   r#   r\   r{   z)Successfully deleted customers with ids: )Zdeleted_customersr]   r|   zDlitellm.proxy.proxy_server.delete_end_user(): Exception occured - {})r"   r   r'   r   r   r#   r3   r=   r   r$   r%   	find_manyrl   rb   joinZdelete_manyr(   r   r   r   )r   rP   r   Zexisting_usersZmissing_user_idsr   r,   r-   r   r.   delete_end_user  s^   !



r   z/customer/listz/end_user/listhttp_requestc           	   
      s   zdddl m} |jtjkr |jtjkr tddd|jid|du r.tddtj	j
id|jjjd	d	d
dI dH }g }|D ]"}| }|drXdD ]
}|d |d qM|tdi | q@|W S  ty } ztdt| t|d}~ww )z
    [Admin-only] List all available customers

    Example curl:
    ```
    curl --location --request GET 'http://0.0.0.0:4000/customer/list'         --header 'Authorization: Bearer sk-1234'
    ```

    r   r   i  r   z&Admin-only endpoint. Your user role={}r   Nr2   TrU   )rX   rK   rY   z]litellm.proxy.management_endpoints.customer_endpoints.list_end_user(): Exception occured - {}r-   )r"   r   Z	user_roleZLitellmUserRolesZPROXY_ADMINZPROXY_ADMIN_VIEW_ONLYr   rb   r8   ra   r9   r$   r%   r   re   ri   rj   r&   r~   r'   r   rk   r(   r   )	r   rP   r   r   Zreturned_responseitemZ	item_dictrp   r,   r-   r-   r.   list_end_user  sJ   	

r   z/customer/daily/activityz/end_user/daily/activity   
   end_user_ids
start_dateend_datemodelapi_keypage	page_sizeexclude_end_user_idsc	                    s   ddl m}	 |	du rtddtjjid| r| dnd}
d}|r+|r)|dnd}i }|
r7dt|
i|d	< |	jj	j
|d
I dH }dd |D }t|	dd|
||||||||dI dH S )zX
    Get daily activity for specific organizations or all accessible organizations.
    r   r   Nr   r   r   ,r   r   r   c                 S   s   i | ]	}|j d |jiqS )alias)r   r   )r4   r,   r-   r-   r.   
<dictcomp>d  s    z/get_customer_daily_activity.<locals>.<dictcomp>Zlitellm_dailyenduserspendrs   )r   Z
table_nameZentity_id_fieldZ	entity_idZentity_metadata_fieldZexclude_entity_idsr   r   r   r   r   r   )r"   r   r   r8   ra   r9   splitr=   r$   r%   r   r   )r   r   r   r   r   r   r   r   rP   r   Zend_user_ids_listZexclude_end_user_ids_listZwhere_conditionZend_user_aliasesZend_user_alias_metadatar-   r-   r.   get_customer_daily_activity1  sF   
r   )0__doc__typingr   r   Zfastapir   r   r   r   r;   Zlitellm._loggingr   Zlitellm.proxy._typesZ$litellm.proxy.auth.user_api_key_authr
   Z8litellm.proxy.management_endpoints.common_daily_activityr   Z8litellm.proxy.management_helpers.object_permission_utilsr   r   Zlitellm.proxy.utilsr   Z>litellm.types.proxy.management_endpoints.common_daily_activityr   ZrouterpostZ
BlockUsersr/   r?   ZNewCustomerRequestrB   rG   rf   r~   rO   ZUserAPIKeyAuthrq   ri   ZQueryr(   ry   ZUpdateCustomerRequestr   ZDeleteCustomerRequestr   r   intr   r-   r-   r-   r.   <module>   s`   +2
  37 AM:	