o
    c۷iPX                     @   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	 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 d dlmZmZmZmZmZmZmZmZmZm Z  d d	l!m"Z" d d
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/G dd de/Z0de)de+de,fddZ1dS )    N)Enum)Generic)Draft7ValidatorSchemaError)assert_never) InvalidAssistantMessageExceptionInvalidFunctionCallException InvalidMessageStructureExceptionInvalidRequestExceptionInvalidSystemPromptExceptionInvalidToolExceptionInvalidToolMessageExceptionInvalidToolSchemaException)
AudioChunkAudioURLChunk)
UATSAssistantMessageAssistantMessageTypeFinetuningAssistantMessageRolesSystemMessageSystemMessageTypeToolMessageTypeUserMessage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/vllm_env/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d4d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eddfd2d3Z&dS )5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__H   s   
z MistralRequestValidator.__init__returnc                 C   s   | j S Nr.   )r0   r)   r)   r*   r-   P   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)
        r5   N) _validate_message_list_structure_validate_message_list_contentr0   r4   r5   r)   r)   r*   validate_messagesT   s   z)MistralRequestValidator.validate_messagesrequestc                 C   sN   | 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 moder6   )r/   r!   r"   modelr
   r:   r4   r5   _validate_toolstools_validate_model_settingsr0   r;   r)   r)   r*   validate_requestd   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   )r0   rB   er)   r)   r*   _validate_function   s   z*MistralRequestValidator._validate_functionr>   c                 C   s   |D ]}|  |j qdS )zC
        Checks:
        - That the tool schemas are valid
        N)rM   rB   )r0   r>   toolr)   r)   r*   r=      s   z'MistralRequestValidator._validate_toolsrH   c                 C      d S r3   r)   r0   rH   r)   r)   r*   _validate_user_message      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
        NrC   rD   rE   )rK   rI   rJ   r   rP   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   rP   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
        rC   rD   rE   N)rI   rJ   rK   r   )r0   rV   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)rW   rB   )r0   rX   rY   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rY   )r      z.Assistant message weight must be either 0 or 1z7Assistant message with prefix True must be last message)r,   boolrT   
tool_callsr   rZ   r/   r!   r#   
isinstancer   weightprefix)r0   rH   rY   rX   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   r\   3Not the same number of function calls and responses#More tool responses than tool calls)roler   rN   	assistantr	   r^   lenr/   r!   r"   r#   )r0   r4   	prev_roleexpected_tool_messagesrH   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 '')re   r   systemuserrf   rN   r	   )r0   r4   previous_rolerH   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 )re   r/   r!   r#   r   rf   r	   r_   r   ra   rm   rN   )r0   rH   r5   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 messager\   z=Conversation must start with a user message or system messager6   N)rg   r	   re   r   rm   rl   r/   r!   r#   ru   rq   rj   r9   r)   r)   r*   r7   3  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
        r\   r[   zUnsupported message type N)	enumeratere   r   rm   rQ   rf   rb   rg   rN   rS   rl   rU   r
   type)r0   r4   idxrH   r)   r)   r*   r8   I  s   z6MistralRequestValidator._validate_message_list_contentc                 C   s"   |j  }d urtd|dd S )Nzreasoning_effort=z  is not supported for this model)reasoning_effortr
   )r0   r;   rz   r)   r)   r*   r?   Z  s   z0MistralRequestValidator._validate_model_settings)F)'r%   r&   r'   r(   r,   r]   __annotations__r!   r$   r1   propertyr-   listr   r:   r   rA   r   rM   r   r=   r   rQ   r   rS   r   rU   r   rW   r   rZ   r   rb   rj   rq   ru   r7   r8   r?   r)   r)   r)   r*   r+   :   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()
    rH   r2   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
        NrC   rD   rE   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.)rK   rI   rJ   r   tool_call_idr
   rP   r)   r)   r*   rS   h  s   

z0MistralRequestValidatorV3._validate_tool_messagerX   rY   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
        nullr   r   r   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)
idrI   rJ   r   r/   r!   r#   r"   rW   rB   )r0   rX   rY   err_messager)   r)   r*   rZ   }  s   
z-MistralRequestValidatorV3._validate_tool_callr5   c                    sJ   t  || | jtjkr|jd ur!|jD ]}| j|dd qd S d S d S )NTr[   )superru   r/   r!   r#   r^   rZ   )r0   rH   r5   rX   	__class__r)   r*   ru     s   

z0MistralRequestValidatorV3._validate_last_message)r%   r&   r'   r(   r   rS   r   r]   rZ   r   ru   __classcell__r)   r)   r   r*   r~   _  s
    "r~   c                       sV   e Zd ZU dZdZeed< dee ddfddZ	dee d	eddf fd
dZ
  ZS )MistralRequestValidatorV5a*  Validator for v5 Mistral requests.

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

    Note:
        For requests containing audio, this validator ensures that no system prompt is present.

    Examples:
        >>> validator = MistralRequestValidatorV5()
    Tr,   r4   r2   Nc                    s   dt dtfdddt dtfdd tfdd|D }|o)t fd	d|D }|rMfd
dt|D } fddt|D }td| d| ddS )zKValidates that system prompts and audio chunks are not used together in v5.rH   r2   c                 S   s
   t | tS r3   )r_   r   rH   r)   r)   r*   
_is_system  s   
zOMistralRequestValidatorV5._validate_system_prompt_and_audio.<locals>._is_systemc                 S   s*   t | tot | jtotdd | jD S )Nc                 s   s    | ]
}t |ttfV  qd S r3   )r_   r   r   ).0chunkr)   r)   r*   	<genexpr>  s    zbMistralRequestValidatorV5._validate_system_prompt_and_audio.<locals>._has_audio.<locals>.<genexpr>)r_   r   rT   r}   anyr   r)   r)   r*   
_has_audio  s
   

zOMistralRequestValidatorV5._validate_system_prompt_and_audio.<locals>._has_audioc                 3       | ]} |d V  qdS r   Nr)   r   rH   r   r)   r*   r         zNMistralRequestValidatorV5._validate_system_prompt_and_audio.<locals>.<genexpr>c                 3   r   r   r)   r   r   r)   r*   r     r   c                       g | ]\}} |d r|qS r   r)   r   irH   r   r)   r*   
<listcomp>      zOMistralRequestValidatorV5._validate_system_prompt_and_audio.<locals>.<listcomp>c                    r   r   r)   r   r   r)   r*   r     r   z!Found system messages at indexes z) and audio chunks in messages at indexes z8. This is not allowed prior to the tokenizer version 13.N)r   r]   r   rw   
ValueError)r0   r4   has_sphas_sp_and_audio
sp_indexesaudio_indexesr)   )r   r   r*   !_validate_system_prompt_and_audio  s   z;MistralRequestValidatorV5._validate_system_prompt_and_audior5   c                    s   t  j||d | | d S )N)r4   r5   )r   r7   r   r9   r   r)   r*   r7     s   z:MistralRequestValidatorV5._validate_message_list_structure)r%   r&   r'   r(   r,   r]   r{   r}   r   r   r7   r   r)   r)   r   r*   r     s
   
 &r   c                   @   s<   e Zd ZdZdee ddfddZdee ddfddZdS )	MistralRequestValidatorV13zValidator for v13 Mistral requests.

    This validator extends v5 functionality by:
    - Adding stricter tool call ID validation: they should be distinct and called.
    - Allowing system prompts with audio chunks
    r4   r2   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 rc   z in assistant messagerd   )setre   r   rN   r   r	   addrf   rg   clearr^   r   r/   r!   r"   r#   )r0   r4   rh   expected_tool_idsobserved_tool_idsrH   r   rX   r)   r)   r*   rj     s@   


zIMistralRequestValidatorV13._validate_tool_calls_followed_by_tool_messagesc                 C   s   dS )z9Allows system prompts and audio chunks to coexist in v13.Nr)   )r0   r4   r)   r)   r*   r     s   z<MistralRequestValidatorV13._validate_system_prompt_and_audio)r%   r&   r'   r(   r}   r   rj   r   r)   r)   r)   r*   r     s    /r   c                   @   s   e Zd ZdeddfddZdS )MistralRequestValidatorV15r;   r2   Nc                 C   rO   r3   r)   r@   r)   r)   r*   r?     rR   z3MistralRequestValidatorV15._validate_model_settings)r%   r&   r'   r   r?   r)   r)   r)   r*   r     s    r   versionr-   r2   c                 C   s   |   t jkrn t jkrn n	  t|d}|S  t jkr& t|d}|S  t jkr3 t|d}|S   t jkr:n t j	kr@n n	  t
|d}|S t jkrVt|d}|S 	 td|   |S )N)r-   zUnsupported tokenizer version: )r    v1v2r+   v3r~   v7r   v11v13r   v15r   r   )r   r-   	validatorr)   r)   r*   get_validator  s&   "



"

r   )2rI   enumr   typingr   
jsonschemar   r   typing_extensionsr   mistral_common.exceptionsr   r   r	   r
   r   r   r   r   &mistral_common.protocol.instruct.chunkr   r   )mistral_common.protocol.instruct.messagesr   r   r   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+   r~   r   r   r   r   r)   r)   r)   r*   <module>   s(    (
0  ';+<