o
    ưi",                     @   s   d 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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 G dd deeZG dd deZ G dd deZ!dS )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
    )Enum)AnyAsyncIteratorIteratorListOptionalTupleUnioncastN)BaseModelResponseIterator)BaseLLMException)AllMessageValuesChatCompletionToolParam)OpenRouterErrorMessage)ModelResponseModelResponseStream   )OpenAIGPTConfig   OpenRouterExceptionc                   @   s$   e Zd ZdZdZdZdZdZdZdS )CacheControlSupportedModelsz4Models that support cache_control in content blocks.ZclaudegeminiZminimaxZglmzz-aiN)	__name__
__module____qualname____doc__ZCLAUDEZGEMINIZMINIMAXZGLMZZAI r   r   b/home/app/Keep/.python/lib/python3.10/site-packages/litellm/llms/openrouter/chat/transformation.pyr      s    r   c                       s  e Zd Zdedef fddZdededededef
 fdd	Zdedefd
dZ		d*dede
e dee
d  dee
e ee
d  f f fddZde
e de
e fddZdede
e dedededef fddZ		d+dedejdededede
e dedededee dee def fdd Zd!ed"edeeejf defd#d$Z	%d,d&eee ee ef d'edee defd(d)Z  ZS )-OpenrouterConfigmodelreturnc                    sb   t  j|d}ztj|ddstj|dr|d |d W n	 ty)   Y nw tt|S )zU
        Allow reasoning parameters for models flagged as reasoning-capable.
        )r    Z
openrouter)r    Zcustom_llm_providerZreasoning_effortZthinking)	superget_supported_openai_paramslitellmZsupports_reasoningappend	Exceptionlistdictfromkeys)selfr    Zsupported_params	__class__r   r   r#   #   s   


z,OpenrouterConfig.get_supported_openai_paramsnon_default_paramsoptional_paramsdrop_paramsc           
         sv   t  ||||}i }|dd }|dd }|dd }	|d ur%||d< |d ur-||d< |	d ur5|	|d< ||d< |S )N
transformsmodelsroute
extra_body)r"   map_openai_paramspop)
r*   r-   r.   r    r/   Zmapped_openai_paramsr3   r0   r1   r2   r+   r   r   r4   2   s    z"OpenrouterConfig.map_openai_paramsc                    s   |   t fd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   s    | ]}|j  v V  qd S N)value).0Zsupported_modelZmodel_lowerr   r   	<genexpr>U   s
    
zFOpenrouterConfig._supports_cache_control_in_content.<locals>.<genexpr>)loweranyr   )r*   r    r   r9   r   "_supports_cache_control_in_contentM   s   z3OpenrouterConfig._supports_cache_control_in_contentNmessagestoolsr   c                    s"   |  |r	||fS t |||S r6   )r=   r"   1remove_cache_control_flag_from_messages_and_tools)r*   r    r>   r?   r+   r   r   r@   Z   s
   
zBOpenrouterConfig.remove_cache_control_flag_from_messages_and_toolsc                 C   s   g }|D ]V}t |}|dd}|durR|d}t|trIt|dkrHg }t|D ]\}}	t |	}
|t|d kr>||
d< ||
 q*||d< n	d||dg|d< |tt	| q|S )aD  
        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)typerD   rA   )
r(   r5   get
isinstancer'   len	enumerater%   r
   r   )r*   r>   Ztransformed_messagesmessageZmessage_dictrA   rB   Zcontent_copyiblockZ
block_dictr   r   r   _move_cache_control_to_contentg   s.   


	z/OpenrouterConfig._move_cache_control_to_contentlitellm_paramsheadersc                    sV   |  |r
| |}|di }t |||||}|| 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.
        r3   usageincludeT)r=   rM   r5   r"   transform_requestupdate)r*   r    r>   r.   rN   rO   r3   responser+   r   r   rR      s   



z"OpenrouterConfig.transform_requestraw_responsemodel_responselogging_objrequest_dataencodingapi_key	json_modec                    s   t  j|||||||||	|
|d}z>| }d|v rG|d rJ|d d}|durMt|ds1i |_d|jvr;i |jd< t||jd d< W |S W |S W |S W |S  tyY   Y |S 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    rU   rV   rW   rX   r>   r.   rN   rY   rZ   r[   rP   ZcostN_hidden_paramsZadditional_headersz$llm_provider-x-litellm-response-cost)r"   transform_responsejsonrF   hasattrr\   floatr&   )r*   r    rU   rV   rW   rX   r>   r.   rN   rY   rZ   r[   Zresponse_jsonZresponse_costr+   r   r   r]      sD   


z#OpenrouterConfig.transform_responseerror_messagestatus_codec                 C      t |||dS )NrJ   rb   rO   r   )r*   ra   rb   rO   r   r   r   get_error_class   s
   z OpenrouterConfig.get_error_classFstreaming_responsesync_streamc                 C   rc   )N)rf   rg   r[   )(OpenRouterChatCompletionStreamingHandler)r*   rf   rg   r[   r   r   r   get_model_response_iterator   s
   z,OpenrouterConfig.get_model_response_iteratorr6   )NN)F)r   r   r   strr'   r#   r(   boolr4   r=   r   r   r   r   r@   rM   rR   httpxResponser   r   r]   intr	   ZHeadersr   re   r   r   ri   __classcell__r   r   r+   r   r   "   s    

,)	
8
r   c                   @   s   e Zd ZdedefddZdS )rh   chunkr!   c              
   C   s  zbd|v r6|d }t d|d |di |dd|d |di d}t|d |d |d d	i d
g }|d D ]}|d d|d d< || q<t|d d|d |d|d |dW S  ty} } ztd| d| dddid
d }~w ty } z|d }~ww )Nerrorz&Message: {}, Metadata: {}, User ID: {}rJ   metadataZuser_id code)rJ   rt   rr   rO   rd   choicesdeltaZ	reasoningZreasoning_contentidzchat.completion.chunkcreatedrP   r    )rw   objectrx   rP   r    ru   z
KeyError: z+, Got unexpected response from OpenRouter: i  zContent-Typezapplication/json)r   formatrF   r   r%   r   KeyErrorr&   )r*   rp   Zerror_chunkra   Znew_choiceschoiceer   r   r   chunk_parser   sP   


	z5OpenRouterChatCompletionStreamingHandler.chunk_parserN)r   r   r   r(   r   r~   r   r   r   r   rh      s    rh   )"r   enumr   typingr   r   r   r   r   r   r	   r
   rl   r$   Z)litellm.llms.base_llm.base_model_iteratorr   Z)litellm.llms.base_llm.chat.transformationr   Zlitellm.types.llms.openair   r   Zlitellm.types.llms.openrouterr   Zlitellm.types.utilsr   r   Zopenai.chat.gpt_transformationr   Zcommon_utilsr   rj   r   r   rh   r   r   r   r   <module>   s     (	 ^