o
    ưif@                     @   s   d 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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 ercdd
lmZ ddlm Z m!Z! ddl"m#Z# eZ$neZ$eZ!eZ eZ#G dd deZ%G dd deZ&dS )z
Transformation for LangGraph API.

LangGraph provides streaming (/runs/stream) and non-streaming (/runs/wait) endpoints
for running agents.

Streaming endpoint: POST /runs/stream
Non-streaming endpoint: POST /runs/wait
    N)TYPE_CHECKINGAnyDictListOptionalTupleUnioncast)verbose_logger)convert_content_list_to_str)
BaseConfigBaseLLMExceptionLangGraphSSEStreamIterator)AllMessageValues)ChoicesMessageModelResponseUsage)Logging)AsyncHTTPHandlerHTTPHandlerCustomStreamWrapperc                   @   s   e Zd ZdZdS )LangGraphErrorz)Exception class for LangGraph API errors.N)__name__
__module____qualname____doc__ r   r   a/home/app/Keep/.python/lib/python3.10/site-packages/litellm/llms/langgraph/chat/transformation.pyr   &   s    r   c                       s  e Zd ZdZ 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	e fd
dZ
deded	ededef
ddZ	d@dee dee d	edededee defddZd	ededefddZde	e de	eeef  fddZd	ede	e dedededefddZdedefdd Zd	ed!ejdefd"d#Z			dAd	ed$ed%ededed&eded'eeed(f  d)ee d*ee defd+d,Z			dAd	ed$ed%ededed&eded'ed( d)ee d*ee defd-d.Z e!defd/d0Z"e!defd1d2Z#		dBd	ed!ejd3e$d%ed4ede	e deded5e%dee d)ee de$fd6d7Z&		dBded	ede	e dededee dee defd8d9Z'd:ed;e(deeej)f de*fd<d=Z+	d@d	ee dee d$ee defd>d?Z,  Z-S )CLangGraphConfigz
    Configuration for LangGraph API.

    LangGraph is a framework for building stateful, multi-actor applications with LLMs.
    It provides a streaming and non-streaming API for running agents.
    c                    s   t  jdi | d S )Nr   )super__init__)selfkwargs	__class__r   r    r#   4   s   zLangGraphConfig.__init__api_baseapi_keyreturnc                 C   s0   ddl m} |p|dpd}|p|d}||fS )z
        Get LangGraph API base and key from params or environment.

        Returns:
            Tuple of (api_base, api_key)
        r   )get_secret_strZLANGGRAPH_API_BASEzhttp://localhost:2024ZLANGGRAPH_API_KEY)Zlitellm.secret_managers.mainr+   )r$   r(   r)   r+   r   r   r    $_get_openai_compatible_provider_info7   s   z4LangGraphConfig._get_openai_compatible_provider_infomodelc                 C   s   dgS )zW
        LangGraph supports minimal OpenAI params since it's an agent runtime.
        streamr   )r$   r-   r   r   r    get_supported_openai_paramsN   s   z+LangGraphConfig.get_supported_openai_paramsnon_default_paramsoptional_paramsdrop_paramsc                 C   s   |S )z8
        Map OpenAI params to LangGraph params.
        r   )r$   r0   r1   r-   r2   r   r   r    map_openai_paramsT   s   
z!LangGraphConfig.map_openai_paramsNlitellm_paramsr.   c                 C   s2   |du rt d|d}|r| dS | dS )z
        Get the complete URL for the LangGraph request.

        Streaming: /runs/stream
        Non-streaming: /runs/wait
        Nz`api_base is required for LangGraph. Set it via LANGGRAPH_API_BASE env var or api_base parameter./z/runs/streamz
/runs/wait)
ValueErrorrstrip)r$   r(   r)   r-   r1   r4   r.   r   r   r    get_complete_url`   s   


z LangGraphConfig.get_complete_urlc                 C   s>   | d}|r	|S d|v r|dd}t|dkr|d S |S )z
        Get the assistant ID from model or optional_params.

        model format: "langgraph/assistant_id" or just "assistant_id"
        assistant_idr5         )getsplitlen)r$   r-   r1   r9   partsr   r   r    _get_assistant_id}   s   
z!LangGraphConfig._get_assistant_idmessagesc                 C   s   g }|D ]?}| dd}| dd}|dkrd}n|dkr d}n	|dkr'd}nd}t|tr2t|}t|ts;t|}|||d q|S )	z
        Convert OpenAI-format messages to LangGraph format.

        OpenAI format: {"role": "user", "content": "..."}
        LangGraph format: {"role": "human", "content": "..."}
        roleusercontent Zhuman	assistantsystem)rB   rD   )r<   
isinstancelistr   strappend)r$   rA   langgraph_messagesmsgrB   rD   Zlanggraph_roler   r   r    %_convert_messages_to_langgraph_format   s"   	

z5LangGraphConfig._convert_messages_to_langgraph_formatheadersc                 C   s   |  ||}| |}|d|id}|dd}	|	r$|dd}
|
|d< d|v r.|d |d< d|v r8|d |d< d	|v rB|d	 |d	< td
|  |S )a=  
        Transform the request to LangGraph format.

        LangGraph request format:
        {
            "assistant_id": "agent",
            "input": {
                "messages": [{"role": "human", "content": "..."}]
            },
            "stream_mode": "messages-tuple"  # for streaming
        }
        rA   )r9   inputr.   Fstream_modezmessages-tupleconfigmetadata	thread_idzLangGraph request payload: )r@   rN   r<   r
   debug)r$   r-   rA   r1   r4   rO   r9   rL   payloadr.   rQ   r   r   r    transform_request   s"   
z!LangGraphConfig.transform_requestresponse_jsonc                 C   s   | dg }t|tr5|r5t|D ]#}t|tr4| dd}| dd}|dks,|dkr4| dd  S q| di }t|trk| dg }t|trk|rkt|D ]}t|trj| dd}|dkrj| dd  S qQtd	 t|S )
z
        Extract content from LangGraph non-streaming response.

        Response format varies, but commonly:
        {
            "messages": [...],  # or could be in different structure
            "values": {...}
        }
        rA   typerE   rB   ZairF   rD   valuesz@Could not extract content from LangGraph response, returning raw)	r<   rH   rI   reverseddictr
   warningjsondumps)r$   rX   rA   rM   msg_typerB   rZ   Zoutput_messagesr   r   r    _extract_content_from_response   s.   



z.LangGraphConfig._extract_content_from_responseraw_responsec                 C      t ||dS )z@
        Return a streaming iterator for SSE responses.
        )responser-   r   )r$   r-   rb   r   r   r    get_streaming_response	  s   z&LangGraphConfig.get_streaming_responsecustom_llm_providerlogging_objdataclientr   	json_modesigned_json_bodyc                 C   s   ddl m}m} ddlm} |du st||s|i d}td|  |j||t	
|d|d}|jd	krAt|jt| d
| j||d}|||||d}|j|ddd|id |S )zF
        Get a CustomStreamWrapper for synchronous streaming.
        r   )r   _get_httpx_clientr   N)paramsz"Making sync streaming request to: TrO   rh   r.   rg      status_codemessager-   rb   completion_streamr-   rf   rg   rE   first stream response receivedcomplete_input_dictrP   r)   original_responseZadditional_args)&litellm.llms.custom_httpx.http_handlerr   rl   litellm.utilsr   rH   r
   rU   postr^   r_   rq   r   rJ   readre   	post_call)r$   r-   rf   rg   r(   rO   rh   rA   ri   rj   rk   r   rl   r   rd   ru   streaming_responser   r   r    get_sync_custom_stream_wrapper  s@   

z.LangGraphConfig.get_sync_custom_stream_wrapperc                    s   ddl m}m} ddlm} |du st||s!|ttdi d}t	d|  |j
||t|d|d	I dH }|jd
krLt|jt| I dH d| j||d}|||||d}|j|ddd|id |S )zG
        Get a CustomStreamWrapper for asynchronous streaming.
        r   )r   get_async_httpx_clientr   NZ	langgraph)Zllm_providerrm   z#Making async streaming request to: Trn   ro   rp   rs   rt   rE   rv   rw   rx   )rz   r   r   r{   r   rH   r	   r   r
   rU   r|   r^   r_   rq   r   rJ   Zareadre   r~   )r$   r-   rf   rg   r(   rO   rh   rA   ri   rj   rk   r   r   r   rd   ru   r   r   r   r    get_async_custom_stream_wrapperR  sF   

z/LangGraphConfig.get_async_custom_stream_wrapperc                 C      dS )z8Indicates that this config has custom streaming support.Tr   r$   r   r   r    has_custom_stream_wrapper  s   z)LangGraphConfig.has_custom_stream_wrapperc                 C   r   )z}
        LangGraph does not use a stream param in request body.
        Streaming is determined by the endpoint URL.
        Fr   r   r   r   r    %supports_stream_param_in_request_body  s   z5LangGraphConfig.supports_stream_param_in_request_bodymodel_responserequest_dataencodingc              
   C   s  zl|  }td|  | |}t|dd}tdd|d}|g|_||_z(ddlm	} |d|d	}|d|d
d}|| }t
|||d}t|d| W |W S  tyl } ztdt|  W Y d}~|W S d}~ww  ty } ztdt|  tdt| |jdd}~ww )zS
        Transform the LangGraph response to LiteLLM ModelResponse format.
        zLangGraph response: rF   )rD   rB   stopr   )Zfinish_reasonindexrr   )token_counterzgpt-3.5-turbo)r-   rA   T)r-   textZcount_response_tokens)prompt_tokenscompletion_tokenstotal_tokensusagez!Failed to calculate token usage: Nz%Error processing LangGraph response: zError processing response: )rr   rq   )r^   r
   rU   ra   r   r   choicesr-   r{   r   r   setattr	Exceptionr]   rJ   errorr   rq   )r$   r-   rb   r   rg   r   rA   r1   r4   r   r)   rj   rX   rD   rr   choicer   r   r   r   r   er   r   r    transform_response  sF   
z"LangGraphConfig.transform_responsec                 C   s   d|d< |rd| |d< |S )zI
        Validate and set up environment for LangGraph requests.
        zapplication/jsonzContent-TypezBearer Authorizationr   )r$   rO   r-   rA   r1   r4   r)   r(   r   r   r    validate_environment  s   z$LangGraphConfig.validate_environmenterror_messagerq   c                 C   rc   )Nrp   )r   )r$   r   rq   rO   r   r   r    get_error_class  s   zLangGraphConfig.get_error_classc                 C   r   )zZ
        LangGraph has native streaming support, so we don't need to fake stream.
        Fr   )r$   r-   r.   rf   r   r   r    should_fake_stream  s   	z"LangGraphConfig.should_fake_stream)N)NNN)NN).r   r   r   r   r#   r   rJ   r   r,   r   r/   r\   boolr3   r8   r@   r   r   rN   rW   ra   httpxResponser   re   LiteLLMLoggingObjrI   r   r   bytesr   r   r   propertyr   r   r   r   r   r   intZHeadersr   r   r   __classcell__r   r   r&   r    r!   ,   st   



$
1&
	

H	

A	

D	

	r!   )'r   r^   typingr   r   r   r   r   r   r   r	   r   Zlitellm._loggingr
   Z8litellm.litellm_core_utils.prompt_templates.common_utilsr   Z)litellm.llms.base_llm.chat.transformationr   r   Z(litellm.llms.langgraph.chat.sse_iteratorr   Zlitellm.types.llms.openair   Zlitellm.types.utilsr   r   r   r   Z*litellm.litellm_core_utils.litellm_loggingr   Z_LiteLLMLoggingObjrz   r   r   r{   r   r   r   r!   r   r   r   r    <module>   s*    
(