o
    پij                     @  s   d Z ddlmZ ddlZddlZddlZddlZddl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mZ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# erddd	l$m%Z% e&e'Z(d
dddZ)dddZ*G dd dZ+dS )zHandler for Anthropic Messages API requests.

Converts Anthropic requests to OpenAI ChatCompletion format, delegates to
OpenAIServingChat for processing, and converts responses back to Anthropic format.
    )annotationsN)TYPE_CHECKINGAsyncGeneratorOptionalUnion)Request)JSONResponseStreamingResponse)
AnthropicContentBlockAnthropicCountTokensRequestAnthropicCountTokensResponseAnthropicDeltaAnthropicErrorAnthropicErrorResponseAnthropicMessagesRequestAnthropicMessagesResponseAnthropicStreamEventAnthropicUsage)ChatCompletionRequestChatCompletionResponseChatCompletionStreamResponseStreamOptionsTool
ToolChoiceToolChoiceFuncName)OpenAIServingChatend_turn
max_tokenstool_use)stoplength
tool_callsdatastr
event_typereturnc                 C  s   d| d|  dS )z=Format an Anthropic SSE event with event type and data lines.zevent: z
data: z

 )r"   r$   r&   r&   \/home/ubuntu/.local/lib/python3.10/site-packages/sglang/srt/entrypoints/anthropic/serving.py_wrap_sse_event5   s   r(   c                   @  sj   e Zd ZdZd-ddZd.ddZd/ddZd0ddZd1ddZd2ddZ	d3d d!Z
d4d'd(Zd5d*d+Zd,S )6AnthropicServingzHandler for Anthropic Messages API requests.

    Acts as a translation layer between Anthropic's Messages API and SGLang's
    OpenAI-compatible chat completion infrastructure.
    openai_serving_chatr   c                 C  s
   || _ d S )N)r*   )selfr*   r&   r&   r'   __init__A   s   
zAnthropicServing.__init__requestr   raw_requestr   r%   &Union[JSONResponse, StreamingResponse]c              
     s   z|  |}W n" ty* } ztd| | jddt|dW  Y d}~S d}~ww |jr8| |||I dH S | |||I dH S )z+Main entry point for /v1/messages endpoint.z&Error converting Anthropic request: %s  invalid_request_errorstatus_code
error_typemessageN)	#_convert_to_chat_completion_request	Exceptionlogger	exception_error_responser#   stream_handle_streaming_handle_non_streaming)r+   r-   r.   chat_requester&   r&   r'   handle_messagesD   s   z AnthropicServing.handle_messagesanthropic_requestr   c              
   C  s  g }|j r8t|j tr|d|j d n#g }|j D ]}|jdkr*|jr*||j qd|}|d|d |jD ]}t|jtrN||j	|jd q;d|j	i}g }g }	|jD ]}|jdkrn|jrn|d|jd qZ|jdkr|j
r|j
dd	}
|j
d
d}|ddd|
 d| id qZ|jdkr|jpdt j d|jpdt|jpi dd}|	| qZ|jdkrt|jtrddd |jD }n
|jrt|jnd}|jp|jpd}|j	dkr|d||d qZ|dd| d qZ|	r|	|d< |r't|dkr"|d d  dkr"|d d |d!< n	||d!< n|	s+q;|| q;||j|j|jp;d"d#}|jd$urI|j|d%< |jd$urT|j|d&< |jd$ur_|j|d'< |jd$urj|j|d(< |jrutd)d*|d+< td3i |}|j rg }|j D ]}|t!d|j|j"pd|j#d,d- q||_ |j$d$ur|j$jd.krd.|_$|S |j$jd/krd/|_$|S |j$jd0krd1|_$|S |j$jdkrt%dt&|j$jd2d-|_$|S |j rd/|_$|S )4zJConvert an Anthropic Messages request to an OpenAI ChatCompletion request.system)rolecontenttext
rC   typerE   image
media_typez	image/pngr"    	image_urlurlzdata:z;base64,)rH   rL   r   call_function)name	arguments)idrH   rO   tool_resultc                 s  s4    | ]}t |tr|d dkr|ddV  qdS )rH   rE   rK   N)
isinstancedictget).0itemr&   r&   r'   	<genexpr>   s    
zGAnthropicServing._convert_to_chat_completion_request.<locals>.<genexpr>usertool)rC   tool_call_idrD   zTool result: r!      r   rH   rD   F)messagesmodelr   r;   Ntemperaturetop_ptop_kr   T)include_usagestream_options)rP   description
parameters)rH   rO   noneautoanyrequired)rP   r&   )'rB   rT   r#   appendrH   rE   joinr^   rD   rC   sourcerV   rR   uuiduuid4hexrP   jsondumpsinputlisttool_use_idlenr_   r   r;   r`   ra   rb   stop_sequencesr   r   toolsr   re   input_schematool_choicer   r   )r+   rA   openai_messagessystem_partsblocksystem_textmsg
openai_msgcontent_partsr!   rJ   r"   	tool_calltool_contentr\   request_datar>   rx   r[   r&   r&   r'   r6   Y   s   






	



 









z4AnthropicServing._convert_to_chat_completion_requestr>   r   c              
     s   t   }t  }| j|}|r| jdd|dS z%t  | }| j||\}}	||_||_||_| j	||	|I dH }
W n  t
y^ } ztd| | jddddW  Y d}~S d}~ww t|
tsl| jddd	dS | |
}t|jd
ddS )zGHandle non-streaming Anthropic request by delegating to OpenAI handler.r0   r1   r2   Nz&Error processing Anthropic request: %s  internal_errorInternal server errorzInternal processing errorTexclude_nonerD   )timeperf_counterr*   _validate_requestr:   _convert_to_internal_requestvalidation_timereceived_timereceived_time_perf_handle_non_streaming_requestr7   r8   r9   rT   r   _convert_responser   
model_dump)r+   r>   rA   r.   r   r   	error_msgr   adapted_requestprocessed_requestresponser?   anthropic_responser&   r&   r'   r=      sN   
	
z&AnthropicServing._handle_non_streaming&Union[StreamingResponse, JSONResponse]c              
     s   t   }t  }| j|}|r| jdd|dS zt  | }| j||\}}	||_||_||_W n  t	yS }
 zt
d|
 | jddddW  Y d}
~
S d}
~
ww t| ||	||d	| jj|d
S )z#Handle streaming Anthropic request.r0   r1   r2   z&Error converting streaming request: %sr   r   r   Nztext/event-stream)rJ   
background)r   r   r*   r   r:   r   r   r   r   r7   r8   r9   r	   _generate_anthropic_streamtokenizer_managercreate_abort_task)r+   r>   rA   r.   r   r   r   r   r   r   r?   r&   r&   r'   r<   5  sP   
z"AnthropicServing._handle_streamingr   AsyncGenerator[str, None]c                 C s  | j |||}d}d}d}d}	d}
dt j }|j}|2 z3 dH W }|ds-q |dd  }|dkr|rKtd	|d
}t	|j
ddd	V  t|	pPdd}tdt|dt|
rb|
ddnd|
rk|
ddnddd}t	|j
dddV  tdd}t	|j
dddV  q zt|}W n# ty   td| tdtdddd}t	|j
dddV  Y q w |rd}tdt|g |t|jr|jjnddddd}t	|j
dddV  |jr|jd jjdkrq |js|jr|jj|jjpdd}
q |jsq |jd }|jdur|j}	q |j}|jr|jD ]}|j}|j}|r||j r||r=td	|d
}t	|j
ddd	V  |d7 }td |t!d!|pLd"t j |j i d#d$}t	|j
ddd V  d}|j"rztd%|td&|j"d'd(}t	|j
ddd%V  q|r|j"rtd%|td&|j"d'd(}t	|j
ddd%V  qq |jdur|jdkr|std |t!d)dd*d$}t	|j
ddd V  d}td%|td+|jd*d(}t	|j
ddd%V  q 6 dS ),z5Convert OpenAI chat stream to Anthropic event stream.Tr   FNmsg_zdata:    z[DONE]content_block_stop)rH   indexr   r   r   message_delta)stop_reasoninput_tokensoutput_tokensr   r   )rH   deltausagemessage_stop)rH   z Failed to parse stream chunk: %serror	api_errorzStream processing errorrH   r5   )rH   r   message_start)rR   rD   r_   r   rK   r]   content_block_startr   toolu_rH   rR   rP   rs   )rH   r   content_blockcontent_block_deltainput_json_delta)rH   partial_json)rH   r   r   rE   rG   
text_delta)#r*   _generate_chat_streamrn   ro   rp   r_   
startswithstripr   r(   model_dump_jsonSTOP_REASON_MAPrV   r   r   r   model_validate_jsonr7   r8   debugr   r   r   prompt_tokenschoicesr   rD   completion_tokensfinish_reasonr!   rR   rO   rP   r
   rQ   )r+   r   r   rA   r.   openai_streamfirst_chunkcontent_block_indexcontent_block_openr   
usage_info
message_idr_   sse_linedata_str
stop_eventr   delta_eventstop_msgchunkerror_eventstart_eventchoicer   tctc_idtc_funcr&   r&   r'   r   g  sb  
















 z+AnthropicServing._generate_anthropic_streamr   r   r   c              
   C  s  |j sttdddg|jdtddddS |j d }g }|jjr+|td|jjd |jjr\|jjD ](}z	t	
|jj}W n t	jtfyL   i }Y nw |td|j|jj|d	 q3t|jpbd
d}tdt j ||j|t|jry|jjnd|jr|jjndddS )zKConvert an OpenAI ChatCompletionResponse to an Anthropic Messages response.rE   rK   rG   r   r   r   )rD   r_   r   r   r   r   r   r   )rR   rD   r_   r   r   )r   r   r
   r_   r   r5   rD   rk   r!   rq   loadsrO   rQ   JSONDecodeError	TypeErrorrR   rP   r   rV   r   rn   ro   rp   r   r   r   )r+   r   r   rD   r   
tool_inputr   r&   r&   r'   r   H  sN   


z"AnthropicServing._convert_responser3   intr4   r#   r5   c                 C  s"   t t||dd}t|| dS )z*Create an Anthropic-format error response.r   )r   )r3   rD   )r   r   r   r   )r+   r3   r4   r5   
error_respr&   r&   r'   r:   |  s   
z AnthropicServing._error_responser   c           
   
     s  zt |j|jd|j|j|jd}| |}W n" ty9 } zt	d| | j
ddt|dW  Y d}~S d}~ww z1| jjjj}| j||}t|jtrTt|j}n| jjj}	t|	|j}tt|d d	W S  ty } zt	d
| | j
ddddW  Y d}~S d}~ww )zHandle /v1/messages/count_tokens endpoint.

        Converts the request to a ChatCompletionRequest, applies the chat
        template via the OpenAI handler to tokenize, and returns the count.
        r]   )r_   r^   r   rB   rx   rz   z)Error converting count_tokens request: %sr0   r1   r2   N)r   r   zError counting tokens: %sr   r   r   )r   r_   r^   rB   rx   rz   r6   r7   r8   r9   r:   r#   r*   r   model_configis_multimodal_process_messagesrT   
prompt_idsrt   rv   	tokenizerencoder   r   r   )
r+   r-   r.   messages_requestr>   r?   r   	processedr   r   r&   r&   r'   handle_count_tokens  sZ   


z$AnthropicServing.handle_count_tokensN)r*   r   )r-   r   r.   r   r%   r/   )rA   r   r%   r   )r>   r   rA   r   r.   r   r%   r   )r>   r   rA   r   r.   r   r%   r   )r   r   rA   r   r.   r   r%   r   )r   r   r%   r   )r3   r   r4   r#   r5   r#   r%   r   )r-   r   r.   r   r%   r   )__name__
__module____qualname____doc__r,   r@   r6   r=   r<   r   r   r:   r   r&   r&   r&   r'   r)   :   s    


 
%
8
2 
b
4r)   )r"   r#   r$   r#   r%   r#   ),r   
__future__r   rq   loggingr   rn   typingr   r   r   r   fastapir   fastapi.responsesr   r	   )sglang.srt.entrypoints.anthropic.protocolr
   r   r   r   r   r   r   r   r   r   &sglang.srt.entrypoints.openai.protocolr   r   r   r   r   r   r   *sglang.srt.entrypoints.openai.serving_chatr   	getLoggerr   r8   r   r(   r)   r&   r&   r&   r'   <module>   s(    0$


