o
    iM                     @   s(  d dl Z d dlmZ d dlmZ d dlmZmZ d dlm	Z	m
Z
mZmZmZmZmZmZ d dlmZmZmZmZmZmZmZmZ d dlmZ d dlmZmZmZm Z  d d	l!m"Z" G d
d de#eZ$G dd deeeeef Z%G dd de%Z&G dd de&Z'G dd de'Z(de"de$de%fddZ)dS )    N)Enum)Generic)Draft7ValidatorSchemaError) InvalidAssistantMessageExceptionInvalidFunctionCallException InvalidMessageStructureExceptionInvalidRequestExceptionInvalidSystemPromptExceptionInvalidToolExceptionInvalidToolMessageExceptionInvalidToolSchemaException)UATSAssistantMessageAssistantMessageTypeFinetuningAssistantMessageRolesSystemMessageTypeToolMessageTypeUserMessageType)ChatCompletionRequest)FunctionFunctionCallToolToolCall)TokenizerVersionc                   @   s   e Zd ZdZdZdZdZdS )ValidationModezEnum for the validation mode.

    Attributes:
        serving: The serving mode.
        finetuning: The finetuning mode.
        test: The test mode.

    Examples:
        >>> mode = ValidationMode.serving
    serving
finetuningtestN)__name__
__module____qualname____doc__r   r   r    r$   r$   ^/home/ubuntu/.local/lib/python3.10/site-packages/mistral_common/protocol/instruct/validator.pyr   %   s
    r   c                   @   s  e Zd ZU dZdZeed< ejfdefddZ	e
defdd	Zd
ee deddfddZdedee fddZdeddfddZdee ddfddZdeddfddZdeddfddZdeddfddZdeddfd d!Zd"ed#eddfd$d%Zd2ded#eddfd&d'Z d
ee ddfd(d)Z!d
ee ddfd*d+Z"dededdfd,d-Z#d
ee deddfd.d/Z$d
ee ddfd0d1Z%dS )3MistralRequestValidatora  Validator for Mistral requests.

    This class validates the structure and content of Mistral requests.

    Examples:
        >>> from mistral_common.protocol.instruct.messages import UserMessage, AssistantMessage
        >>> validator = MistralRequestValidator()
        >>> messages = [UserMessage(content="Hello how are you ?")]
        >>> validator.validate_messages(messages, False)
    F_allow_tool_call_and_contentmodec                 C   s
   || _ dS )zInitializes the `MistralRequestValidator`.

        Args:
            mode: The validation mode. Defaults to ValidationMode.test.
        N_mode)selfr(   r$   r$   r%   __init__D   s   
z MistralRequestValidator.__init__returnc                 C   s   | j S Nr)   )r+   r$   r$   r%   r(   L   s   zMistralRequestValidator.modemessagescontinue_final_messageNc                 C   s   | j ||d | | dS )a  Validates the list of messages.

        Args:
            messages: The list of messages to validate.
            continue_final_message: Whether to continue the final message.

        Examples:
            >>> from mistral_common.protocol.instruct.messages import UserMessage, AssistantMessage
            >>> validator = MistralRequestValidator()
            >>> messages = [AssistantMessage(content="Hi"), UserMessage(content="Hello")]
            >>> validator.validate_messages(messages, False)
        r0   N) _validate_message_list_structure_validate_message_list_contentr+   r/   r0   r$   r$   r%   validate_messagesP   s   z)MistralRequestValidator.validate_messagesrequestc                 C   sD   | j tjkr|jdu rtd| j|j|jd | |j	pg  |S )a  Validates the request

        Args:
            request: The request to validate.

        Returns:
            The validated request.

        Examples:
            >>> from mistral_common.protocol.instruct.messages import UserMessage
            >>> validator = MistralRequestValidator()
            >>> request = ChatCompletionRequest(messages=[UserMessage(content="Hello")])
            >>> validated_request = validator.validate_request(request)
        Nz1Model name parameter is required for serving moder1   )
r*   r   r   modelr	   r5   r/   r0   _validate_toolstools)r+   r6   r$   r$   r%   validate_request`   s   
z(MistralRequestValidator.validate_requestfunctionc              
   C   s^   zt |j W n ty } ztd|j d}~ww td|js-t	d|j ddS )zE
        Checks:
        - That the function schema is valid
        zInvalid tool schema: N^[a-zA-Z0-9_-]{1,64}$Function name was [ but must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64.)
r   check_schema
parametersr   r   messagerematchnamer   )r+   r;   er$   r$   r%   _validate_function|   s   z*MistralRequestValidator._validate_functionr9   c                 C   s   |D ]}|  |j qdS )zC
        Checks:
        - That the tool schemas are valid
        N)rF   r;   )r+   r9   toolr$   r$   r%   r8      s   z'MistralRequestValidator._validate_toolsrA   c                 C   s   d S r.   r$   r+   rA   r$   r$   r%   _validate_user_message   s   z.MistralRequestValidator._validate_user_messagec                 C   s2   |j durtd|j std|j  ddS dS )z:
        Checks:
        - The tool name is valid
        Nr<   r=   r>   )rD   rB   rC   r   rH   r$   r$   r%   _validate_tool_message   s   
z.MistralRequestValidator._validate_tool_messagec                 C   s   |j du r	tddS )zF
        Checks:
        - That the system prompt has content
        NzSystem prompt must have content)contentr
   rH   r$   r$   r%   _validate_system_message   s   
z0MistralRequestValidator._validate_system_messagefunction_callc                 C   s$   t d|jstd|j ddS )zK
        Checks:
        - That the function call has a valid name
        r<   r=   r>   N)rB   rC   rD   r   )r+   rM   r$   r$   r%   _validate_function_call   s
   z/MistralRequestValidator._validate_function_call	tool_callis_last_messagec                 C   s   |  |j dS )zK
        Checks:
        - That the tool call has a valid function
        N)rN   r;   )r+   rO   rP   r$   r$   r%   _validate_tool_call   s   z+MistralRequestValidator._validate_tool_callc                 C   s   | j st|jt|jkrtd|jdur#|jD ]	}| j||d q| jtjkr<t	|t
r<|jdur<|jdvr<td|jrE|sGtddS dS )z
        Checks:
        - That the assistant message has either text or tool_calls, but not both
        - That the tool calls are valid
        zGAssistant message must have either content or tool_calls, but not both.NrP   )r      z.Assistant message weight must be either 0 or 1z7Assistant message with prefix True must be last message)r'   boolrK   
tool_callsr   rQ   r*   r   r   
isinstancer   weightprefix)r+   rA   rP   rO   r$   r$   r%   _validate_assistant_message   s   	

z3MistralRequestValidator._validate_assistant_messagec                 C   s   d}d}|D ]0}|du r|j }q|j tjkr|d8 }n|j tjkr3|dkr)td|jdur3t|j}|j }q|dkrE| jtj	krEtd|dk rS| jtj
krUtddS dS )z
        Checks:
        - That the number of tool calls and tool messages are the same
        - That the tool calls are followed by tool messages
        Nr   rS   3Not the same number of function calls and responses#More tool responses than tool calls)roler   rG   	assistantr   rU   lenr*   r   r   r   )r+   r/   	prev_roleexpected_tool_messagesrA   r$   r$   r%   ._validate_tool_calls_followed_by_tool_messages   s&   


zFMistralRequestValidator._validate_tool_calls_followed_by_tool_messagesc                 C   s   d}|D ]O}|j }|durQ|tjkrtjtjtjh}n'|tjkr)tjtjtjh}n|tjkr7tjtjtjh}n|tjkrBtjtjh}||vrQtd| d| d|}qdS )zp
        Validates the order of the messages, for example user -> assistant -> user -> assistant -> ...
        NzUnexpected role 'z' after role '')r\   r   systemuserr]   rG   r   )r+   r/   previous_rolerA   current_roleexpected_rolesr$   r$   r%   _validate_message_order   s$   



z/MistralRequestValidator._validate_message_orderc                 C   s   |j }| jtjkr|tjkrtd| |rtdd S t|to(|j	 o(| }|j tj
tjhv}|r=|r=td| |rN|tjksG|j	rPtd| d S d S )Nz4Expected last role Assistant for finetuning but got z0Cannot continue final message in finetuning modezuExpected last role User or Tool (or Assistant with prefix or continue_final_message set to True) for serving but got zkExpected last role Assistant with prefix False for serving with continue_final_message set to True but got )r\   r*   r   r   r   r]   r   rV   r   rX   rd   rG   )r+   rA   r0   last_message_rolebad_assistantbad_roler$   r$   r%   _validate_last_message  s0   
z.MistralRequestValidator._validate_last_messagec                 C   s   t |dkr
tdt |dkr|d jtjtjhvrtd| jtjks+t |dkr4| j	|d |d | 
| | | dS )z
        Validates the structure of the list of messages

        For example the messages must be in the correct order of user/assistant/tool
        r   z+Conversation must have at least one messagerS   z=Conversation must start with a user message or system messager1   N)r^   r   r\   r   rd   rc   r*   r   r   rl   rh   ra   r4   r$   r$   r%   r2   -  s   
z8MistralRequestValidator._validate_message_list_structurec                 C   s   t |D ]D\}}|jtjkr| | q|jtjkr(| j||t|d kd q|jtjkr4| 	| q|jtj
kr@| | qtdt| dS )z7
        Validates the content of the messages
        rS   rR   zUnsupported message type N)	enumerater\   r   rd   rI   r]   rY   r^   rG   rJ   rc   rL   r	   type)r+   r/   idxrA   r$   r$   r%   r3   C  s   z6MistralRequestValidator._validate_message_list_content)F)&r    r!   r"   r#   r'   rT   __annotations__r   r   r,   propertyr(   listr   r5   r   r:   r   rF   r   r8   r   rI   r   rJ   r   rL   r   rN   r   rQ   r   rY   ra   rh   rl   r2   r3   r$   r$   r$   r%   r&   6   s*   
 	 r&   c                       sV   e Zd ZdZdeddfddZdededdfd	d
Zde	deddf fddZ
  ZS )MistralRequestValidatorV3zValidator for v3 Mistral requests.

    This validator adds additional validation for tool call IDs.

    Examples:
        >>> validator = MistralRequestValidatorV3()
    rA   r-   Nc                 C   s`   |j durtd|j std|j  d|jdu rtdtd|js.td|j ddS )	zZ
        Checks:
        - The tool name is valid
        - Tool call id is valid
        Nr<   r=   r>   zTool call id has to be defined.^[a-zA-Z0-9]{9}$Tool call id was / but must be a-z, A-Z, 0-9, with a length of 9.)rD   rB   rC   r   tool_call_idr	   rH   r$   r$   r%   rJ   ^  s   

z0MistralRequestValidatorV3._validate_tool_messagerO   rP   c                 C   s~   |j dkrtd|j std|j  d| jtjkr(|s(|j dkr(d}t|| jtjkr7|j dkr7td| |j	 dS )z<
        Validate that the tool call has a valid ID
        nullru   rv   rw   zXTool call id of assistant message that is not last has to be defined in finetuning mode.z/Tool call id has to be defined in serving mode.N)
idrB   rC   r   r*   r   r   r   rN   r;   )r+   rO   rP   err_messager$   r$   r%   rQ   s  s   
z-MistralRequestValidatorV3._validate_tool_callr0   c                    sJ   t  || | jtjkr|jd ur!|jD ]}| j|dd qd S d S d S )NTrR   )superrl   r*   r   r   rU   rQ   )r+   rA   r0   rO   	__class__r$   r%   rl     s   

z0MistralRequestValidatorV3._validate_last_message)r    r!   r"   r#   r   rJ   r   rT   rQ   r   rl   __classcell__r$   r$   r}   r%   rt   U  s
    "rt   c                   @   s   e Zd ZU dZdZeed< dS )MistralRequestValidatorV5zValidator for v5 Mistral requests.

    This validator allows for both tool calls and content in the assistant message.

    Examples:
        >>> validator = MistralRequestValidatorV5()
    Tr'   N)r    r!   r"   r#   r'   rT   rq   r$   r$   r$   r%   r     s   
 r   c                   @   s"   e Zd Zdee ddfddZdS )MistralRequestValidatorV13r/   r-   Nc                 C   s@  d}t  }t  }|D ]m}|du r|j}q
|jtjkr;|j}||v r)td| d||vr5td| d|| n9|jtjkrtt|t|krMtd|	  |	  |j
durt|j
D ]}|j|v rmtd|j d||j q]|j}q
t|t|kr| jtjkrtdt|t|k r| jtjkrtddS dS )z
        Checks:
        - That the number and ids of tool calls and tool messages are the same
        - That the tool calls are followed by tool messages
        - That tool calls have distinct ids for a given assistant message
        NzDuplicate tool call id z in tool resultszUnexpected tool call id rZ   z in assistant messager[   )setr\   r   rG   rx   r   addr]   r^   clearrU   rz   r*   r   r   r   )r+   r/   r_   expected_tool_idsobserved_tool_idsrA   rx   rO   r$   r$   r%   ra     s@   


zIMistralRequestValidatorV13._validate_tool_calls_followed_by_tool_messages)r    r!   r"   rs   r   ra   r$   r$   r$   r%   r     s    r   versionr(   r-   c                 C   sn   | t jkrt|d}|S | t jkrt|d}|S | t jkr$t|d}|S | t jkr0t|d}|S t	d|  )N)r(   zUnsupported tokenizer version: )
r   v2r&   v3rt   v7r   v13r   
ValueError)r   r(   	validatorr$   r$   r%   get_validator  s   








r   )*rB   enumr   typingr   
jsonschemar   r   mistral_common.exceptionsr   r   r   r	   r
   r   r   r   )mistral_common.protocol.instruct.messagesr   r   r   r   r   r   r   r   (mistral_common.protocol.instruct.requestr   +mistral_common.protocol.instruct.tool_callsr   r   r   r   %mistral_common.tokens.tokenizers.baser   strr   r&   rt   r   r   r   r$   r$   r$   r%   <module>   s"    ((

  !;1