o
    ưi                     @   s^  d dl Z d dlZd dlmZmZmZmZmZmZm	Z	m
Z
 d dlmZ d dlm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mZmZmZmZmZm Z  erd d
l!m"Z" d dl#m$Z% d dl&m'Z' d dl(m)Z* d dl+m,Z, d dl-m.Z.m/Z/m0Z0 d dl1m2Z2 e
e%ef Z$neZ$eZ*eZ,eZ.eZ/eZ0eZ3eZ4eZ2e 5de j6Z7G dd dZ8dS )    N)TYPE_CHECKINGAnyAsyncGeneratorDictListOptionalTupleUnion)	BaseModelverbose_logger)/DEFAULT_MAX_RECURSE_DEPTH_SENSITIVE_DATA_MASKER)ArgillaItem)AllMessageValuesChatCompletionRequest)
PromptSpec)AdapterCompletionStreamWrapper	CallTypesCallTypesLiteralLLMResponseTypesModelResponseModelResponseStreamStandardCallbackDynamicParamsStandardLoggingPayload)HTTPException)Span)	DualCache)Logging)UserAPIKeyAuth)MCPPostCallResponseObjectMCPPreCallRequestObjectMCPPreCallResponseObject)PreRoutingHookResponsezOdata:(?:application|image|audio|video)/[a-zA-Z0-9.+-]+;base64,[A-Za-z0-9+/=\s]+c                    @   s  e Zd Z		ddededdfddZedd	ee dee fd
dZ	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdedededee fddZdd  Zd!d" Z						ddedee d#ed$ee d%ee d&ed'ed(ee d)eee  d*ee d+ee d,ee d-ee deeee ef fd.d/Z					ddedee d#ed$ee d%ee d&ed(ee d*ee d+ee d,ee d-ee deeee ef fd0d1Z	 			dded2edeeeeef   d3eeeef  d4ee dee fd5d6Z 		dded7edeee  d2ee d8ee! dee fd9d:Z"deee#f d;ee$ dee fd<d=Z%d>ed8ee! dee fd?d@Z&d>edee fdAdBZ'dCedDe(d;ee$ dee( fdEdFZ)dCedGe#d;ee$ dee# fdHdIZ*dJe+dKee defdLdMZ,dKededNe+fdOdPZ-dKededNe+fdQdRZ.dee/ fdSdTZ0dDe1dee2 fdUdVZ3dWe#dee4 fdXdYZ5dZe6d[ee7 dee6 fd\d]Z8	 d^e9d_d`daed;e:deee+eef  f
dbdcZ;	ddaed^e9dDe#ddeeeef  deeeef  f
dedfZ<	ddCedNe+d^e9dgee dedh f
didjZ=daed^e9dDe(de#fdkdlZ>dedme#d;edeee#f fdndoZ?dedme#d;edeee#f fdpdqZ@daed^e9d;e:de#fdrdsZAd^e9dDede#fdtduZBd^e9dDe#dCedeCeDdf fdvdwZEdxdy ZFdzd{ ZGd|d} ZHd~d ZIdeJdeeJ fddZKdDe#dedee d)eee  dedededeeef fddZLd)ededee dDe#de#dedddedede#fddZMdDe#dedee d)eee  dedededeeef fddZNd)ededee dDe#dedddedede#fddZOde7fddZPde7dededdfddZQdededefddZR	dd2ee dee fddZSdedefddZTdedee fddZUd	efddZVeWfdddeddfddZXeWfdddeddfddZYdeWfde#dedede#fddZZde#defddZ[eWfdee# dedeeee#f  fddZ\dS )CustomLoggerFTturn_off_message_loggingmessage_loggingreturnNc                 K   s   || _ || _dS )a  
        Args:
            turn_off_message_logging: bool - if True, the message logging will be turned off. Message and response will be redacted from StandardLoggingPayload.
            message_logging: bool - deprecated param, use `turn_off_message_logging` instead
        N)r%   r$   )selfr$   r%   kwargs r)   Y/home/app/Keep/.python/lib/python3.10/site-packages/litellm/integrations/custom_logger.py__init__E   s   zCustomLogger.__init__callback_namec                 C   s   | du rg S |   }ddi}|||}zddlm} W n ty'   g  Y S w | }t||d}|du r7g S t|dd}|sAg S t|S )a2  
        Return the environment variables associated with a given callback
        name as defined in the proxy callback registry.

        Args:
            callback_name: The name of the callback to look up.

        Returns:
            List[str]: A list of required environment variable names.
        NZlangfuse_otelZlangfuser   )AllCallbacksZlitellm_callback_params)lowergetlitellm.proxy._typesr-   	Exceptiongetattrlist)r,   Znormalized_nameZ	alias_maplookup_namer-   	callbacksZcallback_infoparamsr)   r)   r*   get_callback_env_varsU   s&   z"CustomLogger.get_callback_env_varsc                 C      d S Nr)   r'   modelmessagesr(   r)   r)   r*   log_pre_api_call{      zCustomLogger.log_pre_api_callc                 C   r8   r9   r)   r'   r(   response_obj
start_timeend_timer)   r)   r*   log_post_api_call~   r>   zCustomLogger.log_post_api_callc                 C   r8   r9   r)   r?   r)   r)   r*   log_stream_event   r>   zCustomLogger.log_stream_eventc                 C   r8   r9   r)   r?   r)   r)   r*   log_success_event   r>   zCustomLogger.log_success_eventc                 C   r8   r9   r)   r?   r)   r)   r*   log_failure_event   r>   zCustomLogger.log_failure_eventc                       d S r9   r)   r?   r)   r)   r*   async_log_stream_event      z#CustomLogger.async_log_stream_eventc                    rG   r9   r)   r:   r)   r)   r*   async_log_pre_api_call   rI   z#CustomLogger.async_log_pre_api_callr;   r<   r(   c                       dS )a  
        Hook called before making the API request to allow modifying request parameters.

        This is specifically designed for modifying the request before it's sent to the provider.
        Unlike async_log_pre_api_call (which is for logging), this hook is meant for transformations.

        Args:
            model: The model name
            messages: The messages list
            kwargs: The request parameters (tools, stream, temperature, etc.)

        Returns:
            Optional[Dict]: Modified kwargs to use for the request, or None if no modifications

        Example:
            ```python
            async def async_pre_request_hook(self, model, messages, kwargs):
                # Convert native tools to standard format
                if kwargs.get("tools"):
                    kwargs["tools"] = convert_tools(kwargs["tools"])
                return kwargs
            ```
        Nr)   r:   r)   r)   r*   async_pre_request_hook   s   z#CustomLogger.async_pre_request_hookc                    rG   r9   r)   r?   r)   r)   r*   async_log_success_event   rI   z$CustomLogger.async_log_success_eventc                    rG   r9   r)   r?   r)   r)   r*   async_log_failure_event   rI   z$CustomLogger.async_log_failure_eventnon_default_params	prompt_idprompt_variablesdynamic_callback_paramslitellm_logging_objprompt_spectoolsprompt_labelprompt_versionignore_prompt_manager_model%ignore_prompt_manager_optional_paramsc                    s   |||fS ax  
        Returns:
        - model: str - the model to use (can be pulled from prompt management tool)
        - messages: List[AllMessageValues] - the messages to use (can be pulled from prompt management tool)
        - non_default_params: dict - update with any optional params (e.g. temperature, max_tokens, etc.) to use (can be pulled from prompt management tool)
        r)   )r'   r;   r<   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   rY   r)   r)   r*    async_get_chat_completion_prompt   s   
z-CustomLogger.async_get_chat_completion_promptc                 C   s
   |||fS rZ   r)   )r'   r;   r<   rO   rP   rQ   rR   rT   rV   rW   rX   rY   r)   r)   r*   get_chat_completion_prompt   s   
z'CustomLogger.get_chat_completion_promptrequest_kwargsinputspecific_deploymentc                    rK   )z
        This hook is called before the routing decision is made.

        Used for the litellm auto-router to modify the request before the routing decision is made.
        Nr)   )r'   r;   r]   r<   r^   r_   r)   r)   r*   async_pre_routing_hook   s   z#CustomLogger.async_pre_routing_hookhealthy_deploymentsparent_otel_spanc                    s   |S r9   r)   )r'   r;   ra   r<   r]   rb   r)   r)   r*   async_filter_deployments      z%CustomLogger.async_filter_deployments	call_typec                    rK   )a  
        Allow modifying the request just before it's sent to the deployment.

        Use this instead of 'async_pre_call_hook' when you need to modify the request AFTER a deployment is selected, but BEFORE the request is sent.

        Used in managed_files.py
        Nr)   )r'   r(   re   r)   r)   r*   async_pre_call_deployment_hook  s   
z+CustomLogger.async_pre_call_deployment_hook
deploymentc                    rG   r9   r)   )r'   rg   rb   r)   r)   r*   async_pre_call_check     z!CustomLogger.async_pre_call_checkc                 C   r8   r9   r)   )r'   rg   r)   r)   r*   pre_call_check  r>   zCustomLogger.pre_call_checkrequest_dataresponsec                    rK   )zh
        Allow modifying / reviewing the response just after it's received from the deployment.
        Nr)   )r'   rk   rl   re   r)   r)   r*   'async_post_call_success_deployment_hook     	z4CustomLogger.async_post_call_success_deployment_hookresponse_chunkc                    rK   )z
        Allow modifying streaming chunks just before they're returned to the user.

        This is called for each streaming chunk in the response.
        Nr)   )r'   rk   ro   re   r)   r)   r*   )async_post_call_streaming_deployment_hook!  s   z6CustomLogger.async_post_call_streaming_deployment_hook	exceptionoriginal_model_groupc                    rG   r9   r)   )r'   rq   rr   r(   r)   r)   r*    log_model_group_rate_limit_error/  ri   z-CustomLogger.log_model_group_rate_limit_errororiginal_exceptionc                    rG   r9   r)   r'   rr   r(   rt   r)   r)   r*   log_success_fallback_event4  ri   z'CustomLogger.log_success_fallback_eventc                    rG   r9   r)   ru   r)   r)   r*   log_failure_fallback_event9  ri   z'CustomLogger.log_failure_fallback_eventc                 C      dS )zt
        Translates the input params, from the provider's native format to the litellm.completion() format.
        Nr)   )r'   r(   r)   r)   r*   !translate_completion_input_params@     z.CustomLogger.translate_completion_input_paramsc                 C   rx   )z\
        Translates the output params, from the OpenAI format to the custom format.
        Nr)   )r'   rl   r)   r)   r*   "translate_completion_output_paramsH  rz   z/CustomLogger.translate_completion_output_paramscompletion_streamc                 C   rx   )z^
        Translates the streaming chunk, from the OpenAI format to the custom format.
        Nr)   )r'   r|   r)   r)   r*   ,translate_completion_output_params_streamingP  rz   z9CustomLogger.translate_completion_output_params_streaminglogged_itemstandard_logging_payloadc                    s
   t d)z
        - Decide if the result should be logged to Argilla.
        - Modify the result before logging to Argilla.
        - Return None if the result should not be logged to Argilla.
        z"async_dataset_hook not implemented)NotImplementedError)r'   r~   r   r)   r)   r*   async_dataset_hookZ  s   
zCustomLogger.async_dataset_hookuser_api_key_dictcacher   datac                    rG   r9   r)   )r'   r   r   r   re   r)   r)   r*   async_pre_call_hookk  rn   z CustomLogger.async_pre_call_hookrequest_headersc                    rK   )af  
        Called after an LLM API call (success or failure) to allow injecting custom HTTP response headers.

        Args:
            - data: dict - The request data.
            - user_api_key_dict: UserAPIKeyAuth - The user API key dictionary.
            - response: Any - The response object (None for failure cases).
            - request_headers: Optional[Dict[str, str]] - The original request headers.

        Returns:
            - Optional[Dict[str, str]]: A dictionary of headers to inject into the HTTP response.
                                        Return None to not inject any headers.
        Nr)   )r'   r   r   rl   r   r)   r)   r*   %async_post_call_response_headers_hookv     z2CustomLogger.async_post_call_response_headers_hooktraceback_strr   c                    rK   )au  
        Called after an LLM API call fails. Can return or raise HTTPException to transform error responses.

        Args:
            - request_data: dict - The request data.
            - original_exception: Exception - The original exception that occurred.
            - user_api_key_dict: UserAPIKeyAuth - The user API key dictionary.
            - traceback_str: Optional[str] - The traceback string.

        Returns:
            - Optional[HTTPException]: Return an HTTPException to transform the error response sent to the client.
                                      Return None to use the original exception.
        Nr)   )r'   rk   rt   r   r   r)   r)   r*   async_post_call_failure_hook  r   z)CustomLogger.async_post_call_failure_hookc                    rG   r9   r)   )r'   r   r   rl   r)   r)   r*   async_post_call_success_hook     z)CustomLogger.async_post_call_success_hookresultc                    s
   ||fS zUFor masking logged request/response. Return a modified version of the request/result.r)   r'   r(   r   re   r)   r)   r*   async_logging_hook  s   zCustomLogger.async_logging_hookc                 C   s   ||fS r   r)   r   r)   r)   r*   logging_hook  s   zCustomLogger.logging_hookc                    rG   r9   r)   )r'   r   r   re   r)   r)   r*   async_moderation_hook  r   z"CustomLogger.async_moderation_hookc                    rG   r9   r)   )r'   r   rl   r)   r)   r*   async_post_call_streaming_hook  s   z+CustomLogger.async_post_call_streaming_hookc                 C  s    |2 z	3 d H W }|V  q6 d S r9   r)   )r'   r   rl   rk   itemr)   r)   r*   'async_post_call_streaming_iterator_hook  s   z4CustomLogger.async_post_call_streaming_iterator_hookc                 C   s\   z||d< ||d< d|d< || |d|  W d S  t y-   |dt   Y d S w Nr;   r<   Zpre_api_calllog_event_typez$Custom Logger - model call details: Custom Logger Error - r1   	traceback
format_excr'   r;   r<   r(   print_verbosecallback_funcr)   r)   r*   log_input_event  s   zCustomLogger.log_input_eventc                    sd   z||d< ||d< d|d< ||I d H  |d|  W d S  t y1   |dt   Y d S w r   r   r   r)   r)   r*   async_log_input_event  s   
z"CustomLogger.async_log_input_eventc                 C   sD   zd|d< ||||| W d S  t y!   |dt   Y d S w NZpost_api_callr   r   r   r'   r(   r@   rA   rB   r   r   r)   r)   r*   	log_event  s   
zCustomLogger.log_eventc                    sL   zd|d< |||||I d H  W d S  t y%   |dt   Y d S w r   r   r   r)   r)   r*   async_log_event  s   zCustomLogger.async_log_eventr@   c                    rK   )z
        This log gets called after the MCP tool call is made.

        Useful if you want to modiy the standard logging payload after the MCP tool call is made.
        Nr)   r?   r)   r)   r*   async_post_mcp_tool_call_hook  rd   z*CustomLogger.async_post_mcp_tool_call_hookstreamcustom_llm_providerc                    
   di fS )a  
        Hook to determine if agentic loop should be executed.

        Called after receiving response from model, before returning to user.

        USE CASE: Enables transparent server-side tool execution for models that
        don't natively support server-side tools. User makes ONE API call and gets
        back the final answer - the agentic loop happens transparently on the server.

        Example use cases:
        - WebSearch: Intercept WebSearch tool calls for Bedrock/Claude, execute
          litellm.search(), return final answer with search results
        - Code execution: Execute code in sandboxed environment, return results
        - Database queries: Execute queries server-side, return data to model
        - API calls: Make external API calls and inject responses back into context

        Flow:
        1. User calls litellm.messages.acreate(tools=[...])
        2. Model responds with tool_use
        3. THIS HOOK checks if tool should run server-side
        4. If True, async_run_agentic_loop executes the tool
        5. User receives final answer (never sees intermediate tool_use)

        Args:
            response: Response from model (AnthropicMessagesResponse or AsyncIterator)
            model: Model name
            messages: Original messages sent to model
            tools: List of tool definitions from request
            stream: Whether response is streaming
            custom_llm_provider: Provider name (e.g., "bedrock", "anthropic")
            kwargs: Additional request parameters

        Returns:
            (should_run, tools):
                should_run: True if agentic loop should execute
                tools: Dict with tool_calls and metadata for execution

        Example:
            # Detect WebSearch tool call
            if has_websearch_tool_use(response):
                return True, {
                    "tool_calls": extract_tool_calls(response),
                    "tool_type": "websearch"
                }
            return False, {}
        Fr)   r'   rl   r;   r<   rU   r   r   r(   r)   r)   r*   async_should_run_agentic_loop  s   8z*CustomLogger.async_should_run_agentic_loop"anthropic_messages_provider_config*anthropic_messages_optional_request_paramslogging_objLiteLLMLoggingObjc
           
         rK   )aI	  
        Hook to execute agentic loop based on context from should_run hook.

        Called only if async_messages_should_run_agentic_loop returns True.

        USE CASE: Execute server-side tools and orchestrate the agentic loop to
        return a complete answer to the user in a single API call.

        What to do here:
        1. Extract tool calls from tools dict
        2. Execute the tools (litellm.search, code execution, DB queries, etc.)
        3. Build assistant message with tool_use blocks
        4. Build user message with tool_result blocks containing results
        5. Make follow-up litellm.messages.acreate() call with results
        6. Return the final response

        Args:
            tools: Dict from async_should_run_agentic_loop
                  Contains tool_calls and metadata
            model: Model name
            messages: Original messages sent to model
            response: Original response from model (with tool_use)
            anthropic_messages_provider_config: Provider config for making requests
            anthropic_messages_optional_request_params: Request parameters (tools, etc.)
            logging_obj: LiteLLM logging object
            stream: Whether response is streaming
            kwargs: Additional request parameters

        Returns:
            Final response after executing agentic loop
            (AnthropicMessagesResponse with final answer)

        Example:
            # Extract tool calls
            tool_calls = agentic_context["tool_calls"]

            # Execute searches in parallel
            search_results = await asyncio.gather(
                *[litellm.asearch(tc["input"]["query"]) for tc in tool_calls]
            )

            # Build messages with tool results
            assistant_msg = {"role": "assistant", "content": [...tool_use blocks...]}
            user_msg = {"role": "user", "content": [...tool_result blocks...]}

            # Make follow-up request
            from litellm.anthropic_interface import messages
            final_response = await messages.acreate(
                model=model,
                messages=messages + [assistant_msg, user_msg],
                max_tokens=anthropic_messages_optional_request_params.get("max_tokens"),
                **anthropic_messages_optional_request_params
            )

            return final_response
        Nr)   )
r'   rU   r;   r<   rl   r   r   r   r   r(   r)   r)   r*   async_run_agentic_loopV  s   Dz#CustomLogger.async_run_agentic_loopc                    r   )zW
        Hook to determine if chat completion agentic loop should be executed.
        Fr)   r   r)   r)   r*   -async_should_run_chat_completion_agentic_loop  s   z:CustomLogger.async_should_run_chat_completion_agentic_loopoptional_paramsc	           	         rK   )ze
        Hook to execute chat completion agentic loop based on context from should_run hook.
        Nr)   )	r'   rU   r;   r<   rl   r   r   r   r(   r)   r)   r*   &async_run_chat_completion_agentic_loop  s   z3CustomLogger.async_run_chat_completion_agentic_loopstandard_logging_objectc                 C   s*   d}g d}|D ]
}| j |||d qdS )a  
        Truncate error strings and message content in logging payload

        Some loggers like DataDog/ GCS Bucket have a limit on the size of the payload. (1MB)

        This function truncates the error string and the message content if they exceed a certain length.
        i'  )Z	error_strr<   rl   )r   
field_name
max_lengthN)_truncate_field)r'   r   ZMAX_STR_LENGTHZfields_to_truncatefieldr)   r)   r*   )truncate_standard_logging_payload_content  s   z6CustomLogger.truncate_standard_logging_payload_contentr   r   c                 C   s@   | |}|rt|}t||kr| j||d||< dS dS dS )aP  
        Helper function to truncate a field in the logging payload

        This converts the field to a string and then truncates it if it exceeds the max length.

        Why convert to string ?
        1. User was sending a poorly formatted list for `messages` field, we could not predict where they would send content
            - Converting to string and then truncating the logged content catches this
        2. We want to avoid modifying the original `messages`, `response`, and `error_str` in the logging payload since these are in kwargs and could be returned to the user
        )textr   N)r/   strlen_truncate_text)r'   r   r   r   Zfield_valueZ	str_valuer)   r)   r*   r     s   
zCustomLogger._truncate_fieldr   c                 C   s    t ||kr|d| d S |S )z&Truncate text if it exceeds max_lengthNzC...truncated by litellm, this logger does not support large content)r   )r'   r   r   r)   r)   r*   r     s   
zCustomLogger._truncate_textc                 C   s,   ddl m}m} |du rdS ||v r|S |S )z
        Select the metadata field to use for logging

        1. If `litellm_metadata` is in the request kwargs, use it
        2. Otherwise, use `metadata`
        r   )LITELLM_METADATA_FIELDOLD_LITELLM_METADATA_FIELDN)litellm.constantsr   r   )r'   r]   r   r   r)   r)   r*   _select_metadata_field  s   	z#CustomLogger._select_metadata_fieldmodel_call_detailsc                 C   s  ddl }ddlm} ddl m}m}m} t| dd}t|dd}|du r(|s(|S ||}	|d}
|
du r7|	S ||
}|rI|D ]	}||v rH||= q?|rd	}d
|pQg vrd|d
durd||d g|d
< d|phg vr|ddur|d }t|t	rd|v rddlm
} ||}t|dtr|d D ]&}t|t	rd|v rt|d tr|d D ]}t|t	rd|v r||d< qq||d< n||||ddgd}| }||d< ||	d< |	S )a  
        Redacts or excludes fields from StandardLoggingPayload before callbacks receive it.

        This method handles two features:
        1. turn_off_message_logging: When True, redacts messages and responses
        2. standard_logging_payload_excluded_fields: Removes specified fields entirely

        Return a modified copy of the provided logging payload.

        This is useful for logging payloads that contain sensitive information.
        r   N)copy)ChoicesMessager   r$   FZ(standard_logging_payload_excluded_fieldsr   zredacted-by-litellmr<   contentrl   output)deepcopyr   r   )message)choices)litellmr   r   r   r   r2   r/   Z
model_dump
isinstancedictr   r3   )r'   r   r   r   r   r   r   r$   Zexcluded_fieldsZmodel_call_details_copyr   Zstandard_logging_object_copyr   Zredacted_strrl   r   Zresponse_copyZoutput_itemZcontent_itemZmodel_responseZmodel_response_dictr)   r)   r*   7redact_standard_logging_payload_from_model_call_details  sl   

zDCustomLogger.redact_standard_logging_payload_from_model_call_details
object_keyc                    rK   )z_
        Get the proxy server request from cold storage using the object key directly.
        Nr)   )r'   r   r)   r)   r*   :get_proxy_server_request_from_cold_storage_with_object_keyg  s   zGCustomLogger.get_proxy_server_request_from_cold_storage_with_object_keyc              
   C   s   z7ddl }ddlm} |j }|D ]}t|dr+|d|  |j|d  W dS q|d| d W dS  ty] } zddlm} |d	| d
t	|  W Y d}~dS d}~ww )z
        Handle callback logging failures by incrementing Prometheus metrics.

        Call this method in exception handlers within your callback when logging fails.
        r   Nr   "increment_callback_logging_failurez)Incrementing callback failure metric for )r,   zENo callback with increment_callback_logging_failure method found for z2. Ensure 'prometheus' is in your callbacks config.z%Error in handle_callback_failure for z: )
r   litellm._loggingr   Zlogging_callback_managerZ_get_all_callbackshasattrdebugr   r1   r   )r'   r,   r   r   Zall_callbacksZcallback_objer)   r)   r*   handle_callback_failurep  s,   



z$CustomLogger.handle_callback_failurepayloadr   	max_depthc                    s   | dg }t|tr|ng }tdt| d |r&| j||d|d< d}| dg p/g D ]}t|trH| dg }t|trH|t|7 }q0td| d |S 	u  
        Removes or redacts base64-encoded file data (e.g., PDFs, images, audio)
        from messages and responses before sending to SQS.

        Behavior:
          • Drop entries with a 'file' key.
          • Drop entries with type == 'file' or any non-text type.
          • Keep untyped or text content.
          • Recursively redact inline base64 blobs in *any* string field, at any depth.
        r<   z%[CustomLogger] Stripping base64 from z	 messages)r<   r   r   r   z0[CustomLogger] Completed base64 strip; retained z content itemsr/   r   r3   r   r   r   _process_messagesr   r'   r   r   Zraw_messagesr<   Ztotal_itemsmr   r)   r)   r*   _strip_base64_from_messages  s*   



z(CustomLogger._strip_base64_from_messagesc                 C   s   | dg }t|tr|ng }tdt| d |r%| j||d|d< d}| dg p.g D ]}t|trG| dg }t|trG|t|7 }q/td| d |S r   r   r   r)   r)   r*    _strip_base64_from_messages_sync  s(   



z-CustomLogger._strip_base64_from_messages_syncr   valuedepthc                    s    krt d d dS t|tr.t|r,t d|dd  d td|S |S t|tr> fd	d
|D S t|t	rP fdd|
 D S |S )z\Recursively redact inline base64 from any nested structure with a max recursion depth limit.z#[CustomLogger] Max recursion depth z reached while redacting base64z[MAX_DEPTH_REACHED]z.[CustomLogger] Redacted inline base64 string: N(   z...z[BASE64_REDACTED]c                    s    g | ]}j | d  dqS    )r   r   r   _redact_base64).0vr   r   r'   r)   r*   
<listcomp>  s    z/CustomLogger._redact_base64.<locals>.<listcomp>c                    s&   i | ]\}}|j | d  dqS r   r   )r   kr   r   r)   r*   
<dictcomp>  s    z/CustomLogger._redact_base64.<locals>.<dictcomp>)r   warningr   r   _BASE64_INLINE_PATTERNsearchr   subr3   r   items)r'   r   r   r   r)   r   r*   r     s*   




zCustomLogger._redact_base64r   c                 C   s8   t |tsdS d|v rdS |d}t |to|dk S )z4Return True if this content item should be retained.TfileFtyper   )r   r   r/   r   )r'   r   ctyper)   r)   r*   _should_keep_content  s   

z!CustomLogger._should_keep_contentc           
      C   s   g }|D ]T}t |tsq|d}t |tr2g }|D ]}| j|dr,|| j||d q||d< n	| j||d|d< t| D ]\}}	|dkrR| j|	|d||< qA|| q|S )Nr   r   )r   r   )r   r   r/   r3   r   appendr   r   )
r'   r<   r   Zfiltered_messagesmsgcontentscleanedckeyvalr)   r)   r*   r     s.   




zCustomLogger._process_messages)FTr9   )NNNNFF)NNNFF)NNF)NN)]__name__
__module____qualname__boolr+   staticmethodr   r   r   r7   r=   rC   rD   rE   rF   rH   rJ   r   rL   rM   rN   r   r   r   r   r   intr   r[   r\   r	   r"   r`   r   rc   r   r   rf   rh   rj   r   rm   rp   r1   rs   rv   rw   r   ry   r   r
   r{   r   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r)   r)   r)   r*   r#   C   sp   
%
	


 	

































	
:	

F

	
	






b
	#
)
)
#r#   )9rer   typingr   r   r   r   r   r   r   r	   Zpydanticr
   r   r   r   r   Z"litellm.types.integrations.argillar   Zlitellm.types.llms.openair   r   Z"litellm.types.prompts.init_promptsr   Zlitellm.types.utilsr   r   r   r   r   r   r   r   Zfastapir   Zopentelemetry.tracer   _SpanZlitellm.caching.cachingr   Z*litellm.litellm_core_utils.litellm_loggingr   r   r0   r   Zlitellm.types.mcpr   r    r!   Zlitellm.types.routerr"   ZMCPDuringCallRequestObjectZMCPDuringCallResponseObjectcompile	MULTILINEr   r#   r)   r)   r)   r*   <module>   sB   ((