
    jj)                         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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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
    )Enum)AnyAsyncIteratorIteratorListOptionalTupleUnioncastN)BaseModelResponseIterator)BaseLLMException)AllMessageValuesChatCompletionToolParam)OpenRouterErrorMessage)ModelResponseModelResponseStream   )OpenAIGPTConfig   OpenRouterExceptionc                       e Zd ZdZdZdZy)CacheControlSupportedModelsz4Models that support cache_control in content blocks.claudegeminiN)__name__
__module____qualname____doc__CLAUDEGEMINI     /Users/manta/Documents/Projects/TheRoad-I1/backend/.venv/lib/python3.12/site-packages/litellm/llms/openrouter/chat/transformation.pyr   r      s    >FFr#   r   c                       e Zd Zde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
ed
      deee	   e
ed
      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ededee	   dededede
e   de
e   def fdZdededeeej,                  f   defdZ	 d deee   ee   ef   dede
e   defdZ xZS )!OpenrouterConfignon_default_paramsoptional_paramsmodeldrop_paramsreturnc                     t         
|   ||||      }i }|j                  dd       }|j                  dd       }|j                  dd       }	|||d<   |||d<   |	|	|d<   ||d<   |S )N
transformsmodelsroute
extra_body)supermap_openai_paramspop)selfr'   r(   r)   r*   mapped_openai_paramsr0   r-   r.   r/   	__class__s             r$   r2   z"OpenrouterConfig.map_openai_params   s      %w8 

 
'++L$?
#''$7"&&w5!'1J|$#)Jx "'Jw 	\* $#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>B   s$      
#> !![0#>s   )loweranyr   )r4   r)   r=   s     @r$   "_supports_cache_control_in_contentz3OpenrouterConfig._supports_cache_control_in_content:   s*     kkm 
#>
 
 	
r#   messagestoolsr   c                 P    | j                  |      r||fS t        | 	  |||      S r9   )rA   r1   1remove_cache_control_flag_from_messages_and_tools)r4   r)   rB   rC   r6   s       r$   rE   zBOpenrouterConfig.remove_cache_control_flag_from_messages_and_toolsG   s6     2259U?"7Lx r#   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 )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)typerJ   rG   )
dictr3   get
isinstancelistlen	enumerateappendr   r   )r4   rB   transformed_messagesmessagemessage_dictrG   rH   content_copyiblock
block_dicts              r$   _move_cache_control_to_contentz/OpenrouterConfig._move_cache_control_to_contentT   s     8:G=L(,,_dCM(&**95gt,7|a'')(1'(:HAu)-eJ CL1$44>K
? ;(//
; ); 3?Y/
 %+$+-:/L+ !''-=|(LM;  > $#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.
        r0   usageincludeT)rA   rZ   r3   r1   transform_requestupdate)	r4   r)   rB   r(   r[   r\   r0   responser6   s	           r$   r`   z"OpenrouterConfig.transform_request   s{     2259::8DH$((r:
7,8_ng
 	
# ("!*D 1HWr#   raw_responsemodel_responselogging_objrequest_dataencoding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)   rc   rd   re   rf   rB   r(   r[   rg   rh   ri   r^   cost_hidden_paramsadditional_headersz$llm_provider-x-litellm-response-cost)r1   transform_responsejsonrM   hasattrrl   float	Exception)r4   r)   rc   rd   re   rf   rB   r(   r[   rg   rh   ri   response_jsonresponse_costr6   s                 r$   rn   z#OpenrouterConfig.transform_response   s    . 3%)#%+) 4 
 	(--/M-'M',B -g 6 : :6 B ,">3CD8:5+>3P3PPNP556JKrw  yF  sGN112FGHno
 	  			s   A:B 	B&%B&error_messagestatus_codec                     t        |||      S )NrT   rv   r\   r   )r4   ru   rv   r\   s       r$   get_error_classz OpenrouterConfig.get_error_class   s     #!#
 	
r#   streaming_responsesync_streamc                     t        |||      S )N)rz   r{   ri   )(OpenRouterChatCompletionStreamingHandler)r4   rz   r{   ri   s       r$   get_model_response_iteratorz,OpenrouterConfig.get_model_response_iterator   s     81#
 	
r#   r9   )NN)F)r   r   r   rL   strboolr2   rA   r   r   r   r	   rE   rZ   r`   httpxResponser   r   rn   intr
   Headersr   ry   r   r   r~   __classcell__)r6   s   @r$   r&   r&      s"   $ $ $ 	$
 $ 
$6
 
 
" <@	 '( 678	
 
t$%x5N0O'PP	Q*$-.*$		*$X '( 	
   
R "&$(66 nn6 &	6
 6 6 '(6 6 6 6 #6 D>6 
6p
 
/2
=B4CV=W
	
 %*	

!(3-s1C]"RS

 

 D>	


 


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: {}rT   metadatauser_id code)rT   r   r   r\   rx   choicesdelta	reasoningreasoning_contentidzchat.completion.chunkcreatedr^   r)   )r   objectr   r^   r)   r   z
KeyError: z+, Got unexpected response from OpenRouter: i  zContent-Typezapplication/json)r   formatrM   r   rR   r   KeyErrorrr   )r4   r   error_chunkru   new_choiceschoicees          r$   chunk_parserz5OpenRouterChatCompletionStreamingHandler.chunk_parser   sg   &	%#Gn 6DKK#I.#
B7#	26
 %V,(__Z<! *))4 -f 5)*599)RH  K	*7=g7J7J;7Ww 34""6* + ';.i(ii(Gn#   	%$QC'RSXRYZ');< 
  	G	s$   C$C' '	D0DDDDN)r   r   r   rL   r   r   r"   r#   r$   r}   r}      s    '$ '+> 'r#   r}   )!r   enumr   typingr   r   r   r   r   r	   r
   r   r   )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   r   r   r&   r}   r"   r#   r$   <module>r      sZ     S S S  O F O @ B = .#t K
 K
\(/H (r#   