o
    ưi&                     @   s   d dl 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 d dlmZmZmZmZmZ d	d
lmZmZ G dd deZG dd deZdS )    )AnyAsyncIteratorIteratorListOptionalTupleUnionN)verbose_logger)XAI_API_BASE)filter_value_from_dictstrip_name_from_messages)get_secret_str)AllMessageValues)ChoicesModelResponseModelResponseStreamPromptTokensDetailsWrapperUsage   )$OpenAIChatCompletionStreamingHandlerOpenAIGPTConfigc                       s  e Zd Zedee fddZdee dee deee ee f fddZdede	fd	d
Z
dedefddZdedefddZ	d+dededede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dedee dedededef fddZededd fd!d"Z	 	 d,ded#ejd$ed%edee dededee dee def fd&d'Zd$ed(edd fd)d*Z  Z S )-XAIChatConfigreturnc                 C   s   dS )NZxai )selfr   r   [/home/app/Keep/.python/lib/python3.10/site-packages/litellm/llms/xai/chat/transformation.pycustom_llm_provider   s   z!XAIChatConfig.custom_llm_providerapi_baseapi_keyc                 C   s$   |pt dpt}|pt d}||fS )Nr
   ZXAI_API_KEY)r   r
   )r   r   r   Zdynamic_api_keyr   r   r   $_get_openai_compatible_provider_info!   s   z2XAIChatConfig._get_openai_compatible_provider_infomodelc              
   C   s   g d}|  |r|d | |r|d ztj|| jdr)|d W |S W |S  tyF } ztd|  W Y d }~|S d }~ww )N)Z
logit_biasZlogprobs
max_tokensnZpresence_penaltyZresponse_formatseedstreamZstream_optionsZtemperatureZtool_choicetoolsZtop_logprobsZtop_puserZweb_search_optionsstopZfrequency_penalty)r    r   Zreasoning_effortz,Error checking if model supports reasoning: )	_supports_stop_reasonappend_supports_frequency_penaltylitellmZsupports_reasoningr   	Exceptionr	   debug)r   r    Zbase_openai_paramser   r   r   get_supported_openai_params(   s$   



z)XAIChatConfig.get_supported_openai_paramsc                 C   s(   d|v rdS d|v rdS d|v rdS dS )Nzgrok-3-miniFgrok-4grok-code-fastTr   r   r    r   r   r   r(   V   s   z#XAIChatConfig._supports_stop_reasonc                 C   s   d|v rdS d|v rdS dS )z
        From manual testing grok-4 does not support `frequency_penalty`

        When sent the model fails from xAI API
        r0   Fr1   Tr   r2   r   r   r   r*   _   s
   z)XAIChatConfig._supports_frequency_penaltyFnon_default_paramsoptional_paramsdrop_paramsc           
      C   s   | j |d}| D ]A\}}|dkr||d< q
|dkr?|d ur?g }|D ]}	t|	d}	|	d ur3||	 q#t|dkr>||d< q
||v rK|d urK|||< q
|S )N)r    Zmax_completion_tokensr!   r%   strictr   )r/   itemsr   r)   len)
r   r3   r4   r    r5   Zsupported_openai_paramsparamvaluer%   Ztoolr   r   r   map_openai_paramsk   s&   


zXAIChatConfig.map_openai_paramsstreaming_responsesync_stream	json_modec                 C   s   t |||dS )N)r<   r=   r>   )!XAIChatCompletionStreamingHandler)r   r<   r=   r>   r   r   r   get_model_response_iterator   s
   z)XAIChatConfig.get_model_response_iteratormessageslitellm_paramsheadersc                    s   t |}t |||||S )zp
        Handle https://github.com/BerriAI/litellm/issues/9720

        Filter out 'name' from messages
        )r   supertransform_request)r   r    rA   r4   rB   rC   	__class__r   r   rE      s   
zXAIChatConfig.transform_requestchoiceNc                 C   s8   | j dkr| jjrt| jjdkrd| _ dS dS dS dS )z
        Helper to fix finish_reason for tool calls when XAI API returns empty string.
        
        XAI API returns empty string for finish_reason when using tools,
        so we need to set it to "tool_calls" when tool_calls are present.
         r   
tool_callsN)finish_reasonmessagerJ   r8   )rH   r   r   r   (_fix_choice_finish_reason_for_tool_calls   s   

z6XAIChatConfig._fix_choice_finish_reason_for_tool_callsraw_responsemodel_responserequest_datac                    s   t  j|||||||||	|
|d}|jr$|jD ]}t|tr#| | qz| }| || W |S  tyL } zt	
d|  W Y d}~|S d}~ww )a2  
        Transform the response from the XAI API.
        
        XAI API returns empty string for finish_reason when using tools,
        so we need to fix this after the standard OpenAI transformation.
        
        Also handles X.AI web search usage tracking by extracting num_sources_used.
        )r    rN   rO   logging_objrP   rA   r4   rB   encodingr   r>   z(Error extracting X.AI web search usage: N)rD   transform_responsechoices
isinstancer   rM   json)_enhance_usage_with_xai_web_search_fieldsr,   r	   r-   )r   r    rN   rO   rQ   rP   rA   r4   rB   rR   r   r>   responserH   raw_response_jsonr.   rF   r   r   rS      s6   


z XAIChatConfig.transform_responserY   c                 C   s   t |dr
|jdu rdS |j}d}|di }t|tr%d|v r%|d}|durN|dkrP|jdu r6t |_t||j_t	|dt| t
d|  dS dS dS )z`
        Extract num_sources_used from X.AI response and map it to web_search_requests.
        usageNnum_sources_usedr   zX.AI web search sources used: )hasattrrZ   getrU   dictZprompt_tokens_detailsr   intZweb_search_requestssetattrr	   r-   )r   rO   rY   rZ   r[   Zresponse_usager   r   r   rW      s   

z7XAIChatConfig._enhance_usage_with_xai_web_search_fields)F)NN)!__name__
__module____qualname__propertyr   strr   r   r   listr/   boolr(   r*   r^   r;   r   r   r   r   r   r@   r   r   rE   staticmethodr   rM   httpxResponserS   rW   __classcell__r   r   rF   r   r      s    
.	

	4r   c                       s&   e Zd Zdedef fddZ  ZS )r?   chunkr   c                    s>   | dg }t|dkrd|v rdi ddg|d< t |S )a  
        Handle xAI-specific streaming behavior.
        
        xAI Grok sends a final chunk with empty choices array but with usage data
        when stream_options={"include_usage": True} is set.
        
        Example from xAI API:
        {"id":"...","object":"chat.completion.chunk","created":...,"model":"grok-4-1-fast-non-reasoning",
         "choices":[],"usage":{"prompt_tokens":171,"completion_tokens":2,"total_tokens":173,...}}
        rT   r   rZ   N)indexdeltarK   )r]   r8   rD   chunk_parser)r   rl   rT   rF   r   r   ro      s   z.XAIChatCompletionStreamingHandler.chunk_parser)ra   rb   rc   r^   r   ro   rk   r   r   rF   r   r?      s    r?   ) typingr   r   r   r   r   r   r   ri   r+   Zlitellm._loggingr	   Zlitellm.constantsr
   Z8litellm.litellm_core_utils.prompt_templates.common_utilsr   r   Zlitellm.secret_managers.mainr   Zlitellm.types.llms.openair   Zlitellm.types.utilsr   r   r   r   r   Zopenai.chat.gpt_transformationr   r   r   r?   r   r   r   r   <module>   s   $  `