o
    :/i                     @   s$  d Z ddlZddlZddlZddlZddlmZ ddlmZm	Z	 ddl
mZ ddlmZ ddlmZ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 dd
lmZmZm Z m!Z!m"Z" ddl#m$Z$ ddl%m&Z&m'Z' ddl(m)Z) erzddl*m+Z+ e,e-Z.de/de/fddZ0G dd de$Z1dS )z&Anthropic Messages API serving handler    N)AsyncGenerator)TYPE_CHECKINGAny)Request)EngineClient)
AnthropicContentBlockAnthropicContextManagementAnthropicCountTokensRequestAnthropicCountTokensResponseAnthropicDeltaAnthropicErrorAnthropicMessagesRequestAnthropicMessagesResponseAnthropicStreamEventAnthropicUsage)ChatTemplateContentFormatOption)RequestLogger)"ChatCompletionNamedToolChoiceParamChatCompletionRequestChatCompletionResponseChatCompletionStreamResponseChatCompletionToolsParam)OpenAIServingChat)ErrorResponseStreamOptions)OpenAIServingModels)OpenAIServingRenderdataeventc                 C   s   d| d|  dS )Nzevent: z
data: z

 )r   r   r   r   o/lsinfo/ai/hellotax_ai/llm_service/venv_vllm/lib/python3.10/site-packages/vllm/entrypoints/anthropic/serving.pywrap_data_with_event4   s   r!   c                       s  e Zd ZdZddddddddededed	d
dedB dedB dede	dede	dedB de	de	f fddZ
edeeef defddZedeeB defddZedeeB deeeef  ddfddZed edeeeef  ddfd!d"Zed#eeef deeeef  ddfd$d%Zed&ed'eeeef  d(eeeef  d)ee deeeef  ddfd*d+Zed(eeeef  ddfd,d-Zed&edeeeef  d'eeeef  ddfd.d/Zedeeeef  ddfd0d1ZedeeB deeeef  defd2d3Zed4edeeB ddfd5d6ZedeeB d4eddfd7d8ZedeeB d4eddfd9d:Z	dFd;ed<e dB de!edf e"B e#B fd=d>Z$d?e%de"fd@dAZ&d?e!edf de!edf fdBdCZ'	dFd;ed<e dB de(e#B fdDdEZ)  Z*S )GAnthropicServingMessagesz+Handler for Anthropic Messages API requestsF N)return_tokens_as_token_idsreasoning_parserenable_auto_toolstool_parserenable_prompt_tokens_detailsenable_force_include_usageengine_clientmodelsresponse_roleopenai_serving_renderr   request_loggerchat_templatechat_template_content_formatr$   r%   r&   r'   r(   r)   c       
            s8   t  j|||||||||	|
|||d dddd| _d S )N)r*   r+   r,   r-   r.   r/   r0   r$   r%   r&   r'   r(   r)   end_turn
max_tokenstool_use)stoplength
tool_calls)super__init__stop_reason_map)selfr*   r+   r,   r-   r.   r/   r0   r$   r%   r&   r'   r(   r)   	__class__r   r    r8   ;   s&   z!AnthropicServingMessages.__init__sourcereturnc                 C   sF   |  d}|dkr|  ddS |  dd}|  dd}d| d| S )	a  Convert an Anthropic image source to an OpenAI-compatible URL.

        Anthropic supports two image source types:
        - base64: {"type": "base64", "media_type": "image/jpeg", "data": "..."}
        - url: {"type": "url", "url": "https://..."}

        For base64 sources, this constructs a proper data URI that
        downstream processors (e.g. vLLM's media connector) can handle.
        typeurlr#   
media_typez
image/jpegr   data:z;base64,)get)r=   source_typerA   r   r   r   r    _convert_image_source_to_urla   s   
z5AnthropicServingMessages._convert_image_source_to_urlanthropic_requestc                 C   sR   g }|  || | |j| | ||}| || | || | || |S )z1Convert Anthropic message format to OpenAI format)_convert_system_message_convert_messagesmessages_build_base_request_handle_streaming_options_convert_tool_choice_convert_tools)clsrF   openai_messagesreqr   r   r    $_convert_anthropic_to_openai_requestv   s   z=AnthropicServingMessages._convert_anthropic_to_openai_requestrO   c                 C   sx   |j sdS t|j tr|d|j d dS d}|j D ]}|jdkr1|jr1|jdr,q||j7 }q|d|d dS )z1Convert Anthropic system message to OpenAI formatNsystemrolecontentr#   textzx-anthropic-billing-header)rR   
isinstancestrappendr?   rV   
startswith)rN   rF   rO   system_promptblockr   r   r    rG      s   


z0AnthropicServingMessages._convert_system_messagerI   c                 C   sH   |D ]}d|j i}t|jtr|j|d< n| ||| || qdS )z+Convert Anthropic messages to OpenAI formatrT   rU   N)rT   rW   rU   rX   _convert_message_contentrY   )rN   rI   rO   msg
openai_msgr   r   r    rH      s   
z*AnthropicServingMessages._convert_messagesr_   c              	   C   s   g }g }g }|j D ]}| ||j|||| q	|r d||d< |r&||d< |rFt|dkr@|d d dkr@|d d |d< d	S ||d< d	S |sL|sNd	S d	S d	S )
z&Convert complex message content blocksr#   	reasoningr6      r   r?   rV   rU   N)rU   _convert_blockrT   joinlen)rN   r^   r_   rO   content_partsr6   reasoning_partsr\   r   r   r    r]      s.   
	z1AnthropicServingMessages._convert_message_contentrT   re   r6   rf   c                 C   s   |j dkr|jr|d|jd dS |j dkr-|jr-| |j}|dd|id dS |j dkr?|jdur?||j dS |j d	krFdS |j d
krS| || dS |j dkrb| |||| dS dS )z Convert individual content blockrV   r?   rV   image	image_urlr@   r?   ri   thinkingNredacted_thinkingr3   tool_result)r?   rV   rY   r=   rE   rk   _convert_tool_use_block_convert_tool_result_block)rN   r\   rT   re   r6   rf   rO   ri   r   r   r    rb      s   


z'AnthropicServingMessages._convert_blockc                 C   sF   |j pdtt  d|jpdt|jpi dd}|| dS )z5Convert tool_use block to OpenAI function call formatcall_functionr#   )name	arguments)idr?   rq   N)rt   inttimerr   jsondumpsinputrY   )rN   r\   r6   	tool_callr   r   r    rn      s   z0AnthropicServingMessages._convert_tool_use_blockc                 C   sF   |dkr|  || dS |jrt|jnd}|dd| d dS )z*Convert tool_result block to OpenAI formatuserr#   rV   zTool result: rg   N)_convert_user_tool_resultrU   rX   rY   )rN   r\   rT   rO   re   tool_result_textr   r   r    ro      s   	z3AnthropicServingMessages._convert_tool_result_blockc           
      C   s   d}g }t |jtr|j}nBt |jtrPg }|jD ]1}t |ts!q|d}|dkr4||dd q|dkrJ|di }| |}	|	rJ||	 qd|}|d|j	pWd|pZdd |ro|d	d
d |D d dS dS )z4Convert user tool_result with text and image supportr#   r?   rV   rh   r=   
tool)rT   tool_call_idrU   r{   c                 S   s   g | ]	}d d|idqS )ri   r@   rj   r   ).0imgr   r   r    
<listcomp>1  s    zFAnthropicServingMessages._convert_user_tool_result.<locals>.<listcomp>rS   N)
rW   rU   rX   listdictrC   rY   rE   rc   tool_use_id)
rN   r\   rO   	tool_texttool_image_urls
text_partsitem	item_typer=   r@   r   r   r    r|     sD   





z2AnthropicServingMessages._convert_user_tool_resultc              
   C   s>   t |trt|j|dS t|j||j|j|j|j|j|jdS )z Build base ChatCompletionRequest)modelrI   )r   rI   r2   max_completion_tokensr4   temperaturetop_ptop_k)	rW   r	   r   r   r2   stop_sequencesr   r   r   )rN   rF   rO   r   r   r    rJ   8  s   
z,AnthropicServingMessages._build_base_requestrP   c                 C   s6   t |trdS |jr|j|_tddd|_dS dS )zHandle streaming configurationNT)include_usagecontinuous_usage_stats)rW   r	   streamr   model_validatestream_options)rN   rP   rF   r   r   r    rK   P  s   

z2AnthropicServingMessages._handle_streaming_optionsc                 C   s|   |j du r
d|_ dS |j j}|dkrd|_ dS |dkr d|_ dS |dkr)d|_ dS |dkr<tdd|j jid	|_ dS dS )
z.Convert Anthropic tool_choice to OpenAI formatNautoanyrequirednoner   rq   rr   r?   rq   )tool_choicer?   r   r   rr   )rN   rF   rP   tool_choice_typer   r   r    rL   _  s"   





z-AnthropicServingMessages._convert_tool_choicec              
   C   s\   |j du rdS g }|j D ]}|td|j|j|jdd q|jdu r)d|_||_ dS )z(Convert Anthropic tools to OpenAI formatNrq   )rr   description
parametersr   r   )toolsrY   r   r   rr   r   input_schemar   )rN   rF   rP   r   r   r   r   r    rM   y  s"   



z'AnthropicServingMessages._convert_toolsrequestraw_requestc                    s   t tjrt d|  | |}t tjr"t d|  | ||I dH }t|t	r2|S t|t
r<| |S | |S )z
        Messages API similar to Anthropic's API.

        See https://docs.anthropic.com/en/api/messages
        for the API specification. This API mimics the Anthropic messages API.
        zReceived messages request %szConvert to OpenAI request %sN)loggerisEnabledForloggingDEBUGdebugmodel_dump_jsonrQ   create_chat_completionrW   r   r   messages_full_convertermessage_stream_converter)r:   r   r   chat_req	generatorr   r   r    create_messages  s   




z(AnthropicServingMessages.create_messagesr   c                 C   s   t |jg |jt|jj|jjdd}|jd }|jdkr d|_	n|jdkr)d|_	n|jdkr1d	|_	g }|j
jrF|td
|j
jt jd |j
jrU|td|j
jd |j
jD ]}td	|j|jjt|jjd}||g7 }qY||_|S )Ninput_tokensoutput_tokens)rt   rU   r   usager   r4   r1   r5   r2   r6   r3   rk   )r?   rk   	signaturerV   rg   r?   rt   rr   ry   )r   rt   r   r   r   prompt_tokenscompletion_tokenschoicesfinish_reasonstop_reasonmessager`   rY   r   uuiduuid4hexrU   r6   rq   rr   rw   loadsrs   )r:   r   resultchoicerU   rz   anthropic_tool_callr   r   r    r     sT   
	


z0AnthropicServingMessages.messages_full_converterc                   s  zXG dd d}d}d }|  i } fdd}dt f fdd}|2 z13 d H W }|d	r=|d
d   d}	|	dkrVtdd}
|
jddd}t|dV  dV  q$t|	}|rtdt	|j
g |jd d t|jro|jjnddddd}d}|jdd}t|dV  q$t|jdkr| D ]}|V  q| j|pd}tdt|dt|jr|jjnd|jr|jjnddd}|jdd}t|dV  q$|jd jd ur|jd j}|jd jj}|d ur"|dkrn; jdkr| D ]}|V  q|t ddd}|V  t jd ur jn jdtd |dd!}|jdd}t|dV  |jd jjd urx|jd jjdkr7nA jd"krR| D ]}|V  q@|t d"dd#}|V  t jd ur\ jn jdtd$|jd jjd#d!}|jdd}t|dV  t|jd jjdkr<|jd jjD ]}|j
d ur|j
||j< |jr|jjnd } j |j
kr|d ur| D ]}|V  q|t d%|j
|i d&}|V  |jr|jj!r j |j
krt jd ur jn jdtd'|jj!d(d!}|jdd}t|dV  q||j}|d ur9|jr9|jj!r9 j |kr9t jd ur  jn jdtd'|jj!d(d!}|jdd}t|dV  qq$q$td)t"d*d+dd,}|jdd}t|d)V  dV  q$6 W d S  t#y } z't$%d- td)t"d*t&|dd,}|jdd}t|d)V  dV  W Y d }~d S d }~ww ).Nc                   @   s2   e Zd Zd
ddZd
ddZdeddfdd	ZdS )zLAnthropicServingMessages.message_stream_converter.<locals>._ActiveBlockStater>   Nc                 S   s(   d| _ d | _d | _d | _d| _d | _d S )Nr   F)content_block_index
block_typeblock_indexblock_signaturesignature_emittedr   r:   r   r   r    r8     s   
zUAnthropicServingMessages.message_stream_converter.<locals>._ActiveBlockState.__init__c                 S   s"   d | _ d | _d | _d| _d | _d S )NF)r   r   r   r   r   r   r   r   r    reset  s
   
zRAnthropicServingMessages.message_stream_converter.<locals>._ActiveBlockState.resetr\   c                 S   sn   |j | _| j| _|j dkrt j| _d| _d | _	d S |j dkr,d | _d| _|j
| _	d S d | _d| _d | _	d S )Nrk   Fr3   T)r?   r   r   r   r   r   r   r   r   r   rt   )r:   r\   r   r   r    start  s   



zRAnthropicServingMessages.message_stream_converter.<locals>._ActiveBlockState.start)r>   N)__name__
__module____qualname__r8   r   r   r   r   r   r   r    _ActiveBlockState  s    

r   Tc                     s   g }  j d u r	| S  j dkr4 jd ur4 js4t jdtd jdd}|jdd}| t|d d _t jdd	}|jdd}| t|d  	    j
d
7  _
| S )Nrk   content_block_deltasignature_delta)r?   r   indexr?   deltaTexclude_unsetcontent_block_stop)r   r?   ra   )r   r   r   r   r   r   r   rY   r!   r   r   )eventschunkr   
stop_chunkstater   r    stop_active_block  s6   


zLAnthropicServingMessages.message_stream_converter.<locals>.stop_active_blockr\   c                    s4   t  jd| d}|jdd}t|d} |  |S )Ncontent_block_start)r   r?   content_blockTr   )r   r   r   r!   r   )r\   r   r   r   r   r   r    start_block-  s   

zFAnthropicServingMessages.message_stream_converter.<locals>.start_blockrB      r~   z[DONE]message_stop)r?   )r   exclude_nonezdata: [DONE]

message_startr   r   )rt   rU   r   r   stop_sequencer   )r?   r   Fr   r4   message_delta)r   )r?   r   r   r#   rk   )r?   rk   r   thinking_deltar   rV   rg   
text_deltar3   r   input_json_delta)r?   partial_jsonerrorinternal_errorzInvalid data format received)r?   r   z"Error in message stream converter.)'r   rZ   striprstripr   r   r!   r   model_validate_jsonr   rt   r   r   r   r   rd   r   r9   rC   r   r   r   r   r`   r   r   r   rU   r6   r   rq   rr   r   rs   r   	Exceptionr   	exceptionrX   )r:   r   r   
first_itemr   tool_index_to_idr   r   r   data_strstop_messager   origin_chunkr   r   r   reasoning_deltastart_eventrz   	tool_namer   error_responseer   r   r    r     s   












L  S
z1AnthropicServingMessages.message_stream_converterc           	         sZ   |  |}| |I dH }t|tr|S |\}}tdd |D }t|t|dd}|S )z6Implements Anthropic's messages.count_tokens endpoint.Nc                 s   s$    | ]}d |v rt |d  V  qdS )prompt_token_idsN)rd   )r   promptr   r   r    	<genexpr>!  s    
z8AnthropicServingMessages.count_tokens.<locals>.<genexpr>)original_input_tokens)r   context_management)rQ   render_chat_requestrW   r   sumr
   r   )	r:   r   r   r   r   _engine_promptsr   responser   r   r    count_tokens  s    

z%AnthropicServingMessages.count_tokens)N)+r   r   r   __doc__r   r   rX   r   r   boolr8   staticmethodr   r   rE   classmethodr   r	   r   rQ   r   rG   rH   r]   rb   rn   ro   r|   rJ   rK   rL   rM   r   r   r   r   r   r   r   r   r
   r  __classcell__r   r   r;   r    r"   8   s>   	
&
# +

3


  6r"   )2r  rw   r   rv   r   collections.abcr   typingr   r   fastapir   vllm.engine.protocolr   #vllm.entrypoints.anthropic.protocolr   r   r	   r
   r   r   r   r   r   r   vllm.entrypoints.chat_utilsr   vllm.entrypoints.loggerr   0vllm.entrypoints.openai.chat_completion.protocolr   r   r   r   r   /vllm.entrypoints.openai.chat_completion.servingr   'vllm.entrypoints.openai.engine.protocolr   r   &vllm.entrypoints.openai.models.servingr   %vllm.entrypoints.serve.render.servingr   	getLoggerr   r   rX   r!   r"   r   r   r   r    <module>   s*   0
