Ë
    uPêja-  ã                   ó  — d Z ddlmZmZ ddlmZ ddlmZmZm	Z	m
Z
 ddlZ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 ddlmZ ddlmZ er
ddlZddlmZ   G d„ de!e«      Z" G d„ de«      Z# G d„ de«      Z$y)z¨
Support for OpenAI's `/v1/chat/completions` endpoint.

Calls done in OpenAI/openai.py as OpenRouter is openai-compatible.

Docs: https://openrouter.ai/docs/parameters
é    )ÚAsyncIteratorÚIterator)ÚEnum)ÚTYPE_CHECKINGÚAnyÚFinalÚcastN)ÚBaseModelResponseIterator)ÚBaseLLMException)ÚAllMessageValuesÚChatCompletionToolParam)ÚOpenRouterErrorMessage)ÚModelResponseÚModelResponseStreamé   )ÚOpenAIGPTConfigé   ©ÚOpenRouterException)ÚLoggingc                   ó$   — e Zd ZdZdZdZdZdZdZy)ÚCacheControlSupportedModelsz4Models that support cache_control in content blocks.ÚclaudeÚgeminiÚminimaxÚglmzz-aiN)	Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚCLAUDEÚGEMINIÚMINIMAXÚGLMÚZAI© ó    úp/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/llms/openrouter/chat/transformation.pyr   r      s   „ Ù>à€FØ€FØ€GØ
€CØ
�Cr'   r   c                   óÊ  ‡ — e Zd Zdedefˆ fd„Zdeeef   dedededef
ˆ fd„Z	dedefd„Z
	 d"ded
ee   ded   d	z  deee   ed   d	z  f   fˆ fd„Zd
ee   dee   fd„Zded
ee   dedededefˆ fd„Z	 	 d#dedej"                  deddded
ee   dededdded	z  ded	z  defˆ fd„Zdededeej*                  z  defd„Z	 d$dee   ee   z  ez  d eded	z  defd!„Zˆ xZS )%ÚOpenrouterConfigÚmodelÚreturnc                 ó  •— t         ‰| �  |¬«      }	 t        j                  |d¬«      st        j                  |¬«      r"|j	                  d«       |j	                  d«       t        t        j                  |«      «      S # t
        $ r Y Œ)w xY w)zU
        Allow reasoning parameters for models flagged as reasoning-capable.
        )r+   Ú
openrouter)r+   Úcustom_llm_providerÚreasoning_effortÚthinking)	ÚsuperÚget_supported_openai_paramsÚlitellmÚsupports_reasoningÚappendÚ	ExceptionÚlistÚdictÚfromkeys)Úselfr+   Úsupported_paramsÚ	__class__s      €r(   r3   z,OpenrouterConfig.get_supported_openai_params*   s‰   ø€ ô #(¡'Ñ"EÈEÐ"EÓ"RÐð	Ü×)Ñ)°È<ÕXÔ\c×\vÑ\vØõ]ð !×'Ñ'Ð(:Ô;Ø ×'Ñ'¨
Ô3ô ”D—M‘MÐ"2Ó3Ó4Ð4øô ò 	Ùð	ús   “AB  Â 	BÂBÚnon_default_paramsÚoptional_paramsÚdrop_paramsc                 ó  •— |j                  d«      dk(  ri |¥ddi¥}t        ‰
| �	  ||||«      }i }|j                  dd «      }|j                  dd «      }|j                  dd «      }	|�||d<   |�||d<   |	�|	|d<   ||d<   |S )Nr0   ÚmaxÚxhighÚ
transformsÚmodelsÚrouteÚ
extra_body)Úgetr2   Úmap_openai_paramsÚpop)r;   r>   r?   r+   r@   Úmapped_openai_paramsrG   rD   rE   rF   r=   s             €r(   rI   z"OpenrouterConfig.map_openai_params9   sÅ   ø€ ð ×!Ñ!Ð"4Ó5¸Ò>Ø!TÐ$6Ð!TÐ8JÈGÑ!TÐä&+¡gÑ&?Ð@RÐTcÐejÐlwÓ&xÐð ˆ
Ø.×2Ñ2°<ÀÓFˆ
Ø*×.Ñ.¨x¸Ó>ˆØ)×-Ñ-¨g°tÓ<ˆØÐ!Ø'1ˆJ�|Ñ$ØÐØ#)ˆJ�xÑ ØÐØ"'ˆJ�wÑØ-7Ð˜\Ñ*Ø#Ð#r'   c                 óT   ‡— |j                  «       Št        ˆfd„t        D «       «      S )z±
        Check if the model supports cache_control in content blocks.

        Returns:
            bool: True if model supports cache_control (Claude or Gemini models)
        c              3   ó:   •K  — | ]  }|j                   ‰v –— Œ y ­w©N)Úvalue)Ú.0Úsupported_modelÚmodel_lowers     €r(   ú	<genexpr>zFOpenrouterConfig._supports_cache_control_in_content.<locals>.<genexpr>\   s   øè ø€ Òk¸O�?×(Ñ(¨KÔ7Ñkùs   ƒ)ÚlowerÚanyr   )r;   r+   rR   s     @r(   Ú"_supports_cache_control_in_contentz3OpenrouterConfig._supports_cache_control_in_contentT   s"   ø€ ð #Ÿ[™[›]ˆÜÓkÔOjÔkÓkÐkr'   NÚmessagesÚtoolsr   c                 óP   •— | j                  |«      r||fS t        ‰| �	  |||«      S rN   )rV   r2   Ú1remove_cache_control_flag_from_messages_and_tools)r;   r+   rW   rX   r=   s       €r(   rZ   zBOpenrouterConfig.remove_cache_control_flag_from_messages_and_tools^   s3   ø€ ð ×2Ñ2°5Ô9Ø˜U�?Ð"ä‘7ÑLÈUÐT\Ð^cÓdÐdr'   c                 ó   — g }|D ]Æ  }t        |«      }|j                  dd«      }|�†|j                  d«      }t        |t        «      r[t        |«      dkD  rWg }t        |«      D ]7  \  }}	t        |	«      }
|t        |«      dz
  k(  r||
d<   |j                  |
«       Œ9 ||d<   n
d||dœg|d<   |j                  t        t        |«      «       ŒÈ |S )a<  
        Move cache_control from message level to content blocks.
        OpenRouter requires cache_control to be inside content blocks, not at message level.

        To avoid exceeding Anthropic's limit of 4 cache breakpoints, cache_control is only
        added to the LAST content block in each message.
        Úcache_controlNÚcontentr   é   Útext)Útyper_   r\   )
r9   rJ   rH   Ú
isinstancer8   ÚlenÚ	enumerater6   r	   r   )r;   rW   Útransformed_messagesÚmessageÚmessage_dictr\   r]   Úcontent_copyÚiÚblockÚ
block_dicts              r(   Ú_move_cache_control_to_contentz/OpenrouterConfig._move_cache_control_to_contenti   sú   € ð ?AÐØò 	NˆGÜ ›=ˆLØ(×,Ñ,¨_¸dÓCˆMàÐ(Ø&×*Ñ*¨9Ó5�ä˜g¤tÔ,ä˜7“| aÒ'Ø')˜Ü(1°'Ó(:ò <™H˜A˜uÜ)-¨e«˜Jà ¤C¨£L°1Ñ$4Ò4Ø>K 
¨?Ñ ;Ø(×/Ñ/°
Õ;ð<ð 3?˜ YÒ/ð
 %+Ø$+Ø-:ñð/�L Ñ+ð !×'Ñ'¬Ô-=¸|Ó(LÕMð;	Nð> $Ð#r'   Úlitellm_paramsÚheadersc                 óÎ   •— | j                  |«      r| j                  |«      }|j                  di «      }t        ‰| �  |||||«      }|j                  |«       d|vrddi|d<   |S )z¥
        Transform the overall request to be sent to the API.

        Returns:
            dict: The transformed request. Sent as the body of the API call.
        rG   ÚusageÚincludeT)rV   rk   rJ   r2   Útransform_requestÚupdate)	r;   r+   rW   r?   rl   rm   rG   Úresponser=   s	           €r(   rq   z"OpenrouterConfig.transform_request“   sx   ø€ ð ×2Ñ2°5Ô9Ø×:Ñ:¸8ÓDˆHà+×/Ñ/°¸bÓAˆ
Ü™'Ñ3°E¸8À_ÐVdÐfmÓnˆØ�‰˜
Ô#ð ˜(Ñ"Ø!*¨DÐ 1ˆH�WÑàˆr'   Úraw_responseÚmodel_responseÚlogging_objÚLiteLLMLoggingObjÚrequest_dataÚencodingztiktoken.Encoding | NoneÚapi_keyÚ	json_modec                 óR  •— t         ‰| �  |||||||||	|
|¬«      }	 |j                  «       }d|v rf|d   ra|d   j                  d«      }|�Kt	        |d«      si |_        d|j
                  vri |j
                  d<   t        |«      |j
                  d   d<   |S # t        $ r Y |S w xY w)zá
        Transform the response from OpenRouter API.

        Extracts cost information from response headers if available.

        Returns:
            ModelResponse: The transformed response with cost information.
        )r+   rt   ru   rv   rx   rW   r?   rl   ry   rz   r{   ro   ÚcostÚ_hidden_paramsÚadditional_headersz$llm_provider-x-litellm-response-cost)r2   Útransform_responseÚjsonrH   Úhasattrr~   Úfloatr7   )r;   r+   rt   ru   rv   rx   rW   r?   rl   ry   rz   r{   Úresponse_jsonÚresponse_costr=   s                 €r(   r€   z#OpenrouterConfig.transform_response¯   së   ø€ ô. ™Ñ3ØØ%Ø)Ø#Ø%ØØ+Ø)ØØØð 4ó 
ˆð 	Ø#/×#4Ñ#4Ó#6ˆMØ˜-Ñ'¨M¸'Ò,BØ'4°WÑ'=×'AÑ'AÀ&Ó'I�Ø Ð,ä" >Ð3CÔDØ8:˜Ô5Ø+°>×3PÑ3PÑPØNP˜×5Ñ5Ð6JÑKÜrwØ%ós�N×1Ñ1Ð2FÑGÐHnÑoð Ðøô	 ò 	ààÐð		ús   �A:B Â	B&Â%B&Úerror_messageÚstatus_codec                 ó   — t        |||¬«      S )N©re   r‡   rm   r   )r;   r†   r‡   rm   s       r(   Úget_error_classz OpenrouterConfig.get_error_classé   s   € Ü"Ø!Ø#Øô
ð 	
r'   Ústreaming_responseÚsync_streamc                 ó   — t        |||¬«      S )N)r‹   rŒ   r{   )Ú(OpenRouterChatCompletionStreamingHandler)r;   r‹   rŒ   r{   s       r(   Úget_model_response_iteratorz,OpenrouterConfig.get_model_response_iteratorð   s   € ô 8Ø1Ø#Øô
ð 	
r'   rN   )NN)F)r   r   r   Ústrr8   r3   r9   ÚobjectÚboolrI   rV   r   ÚtuplerZ   rk   rq   ÚhttpxÚResponser   r€   ÚintÚHeadersr   rŠ   r   r   r   r�   Ú__classcell__)r=   s   @r(   r*   r*   )   s=  ø„ ð5°ð 5¸õ 5ð$à   f Ñ-ð$ð ð$ð ð	$ð
 ð$ð 
õ$ð6l¸ð lÀó lð 9=ñ		eàð	eð Ð'Ñ(ð	eð Ð-Ñ.°Ñ5ð		eð
 
ˆtÐ$Ñ% tÐ,EÑ'FÈÑ'MÐMÑ	Nõ	eð($°tÐ<LÑ7Mð ($ÐRVÐWgÑRhó ($ðTàðð Ð'Ñ(ðð ð	ð
 ðð ðð 
õðN #Ø!%ñ8àð8ð —n‘nð8ð &ð	8ð
 )ð8ð ð8ð Ð'Ñ(ð8ð ð8ð ð8ð -ð8ð �t‘ð8ð ˜$‘;ð8ð 
õ8ðt
¨Sð 
¸sð 
ÈTÐTY×TaÑTaÑMað 
Ðfvó 
ð "'ñ	

à$ S™M¨M¸#Ñ,>Ñ>ÀÑNð

ð ð

ð ˜$‘;ð	

ð
 
÷

r'   r*   c                   ó   — e Zd Zdedefd„Zy)rŽ   Úchunkr,   c           
      ó8  — 	 d|v r�|d   }t        dj                  |d   |j                  di «      |j                  dd«      «      |d   |j                  di «      ¬«      }t        |d   |d   |d   j                  d	i «      ¬
«      ‚g }|d   D ]-  }|d   j                  d«      |d   d<   |j	                  |«       Œ/ t        |d   d|d   |j                  d«      |d   |¬«      S # t        $ r}t        d|› d|› �dddi¬
«      ‚d }~wt        $ r}|‚d }~ww xY w)NÚerrorz&Message: {}, Metadata: {}, User ID: {}re   ÚmetadataÚuser_idÚ Úcode)re   r    r�   rm   r‰   ÚchoicesÚdeltaÚ	reasoningÚreasoning_contentÚidzchat.completion.chunkÚcreatedro   r+   )r¥   r‘   r¦   ro   r+   r¡   z
KeyError: z+, Got unexpected response from OpenRouter: i�  zContent-Typezapplication/json)r   ÚformatrH   r   r6   r   ÚKeyErrorr7   )r;   rš   Úerror_chunkr†   Únew_choicesÚchoiceÚes          r(   Úchunk_parserz5OpenRouterChatCompletionStreamingHandler.chunk_parserþ   sl  € ð&	à˜%ÑØ%*¨7¡^�Ü'=ØD×KÑKØ# IÑ.Ø#Ÿ™¨
°BÓ7Ø#Ÿ™¨	°2Ó6óð
 % VÑ,Ø(Ÿ_™_¨Z¸Ó<ô(�ô *Ø)¨)Ñ4Ø -¨fÑ 5Ø)¨*Ñ5×9Ñ9¸)ÀRÓHôð ð "$ˆKØ 	Ñ*ò +�Ø7=¸g±×7JÑ7JÈ;Ó7W��w‘Ð 3Ñ4Ø×"Ñ" 6Õ*ð+ô 'Ø˜‘;Ø.Ø˜iÑ(Ø—i‘i Ó(Ø˜G‘nØ#ôð øô ò 	Ü%Ø$ Q CÐ'RÐSXÐRYÐZØØ'Ð);Ð<ôð ûô
 ò 	ØˆGûð	ús$   ‚C$C' Ã'	DÃ0DÄDÄDÄDN)r   r   r   r9   r   r­   r&   r'   r(   rŽ   rŽ   ý   s   „ ð' $ð 'Ð+>ô 'r'   rŽ   )%r    Úcollections.abcr   r   Úenumr   Útypingr   r   r   r	   r”   r4   Ú)litellm.llms.base_llm.base_model_iteratorr
   Ú)litellm.llms.base_llm.chat.transformationr   Úlitellm.types.llms.openair   r   Úlitellm.types.llms.openrouterr   Úlitellm.types.utilsr   r   Úopenai.chat.gpt_transformationr   Úcommon_utilsr   ÚtiktokenÚ*litellm.litellm_core_utils.litellm_loggingr   rw   r�   r   r*   rŽ   r&   r'   r(   ú<module>rº      sf   ðñ÷ 4Ý ß 2Ó 2ã ã Ý OÝ Fß OÝ @ß Bå =Ý .áÛåWô # tô ôQ
�ô Q
ôh(Ð/Hõ (r'   