U
    h                     @   s   d Z ddlmZ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 dd	lmZ ed
dddG dd deZdS )z6Chain that carries on a conversation and calls an LLM.    )DictList)
deprecated)
BaseMemory)BasePromptTemplate)Fieldroot_validator)PROMPT)LLMChain)ConversationBufferMemoryz0.2.7zRunnableWithMessageHistory: https://python.langchain.com/v0.2/api_reference/core/runnables/langchain_core.runnables.history.RunnableWithMessageHistory.htmlz1.0)ZsincealternativeZremovalc                   @   s   e Zd ZU dZeedZeed< e	Z
eed< dZeed< dZeed< G d	d
 d
ZeedddZeee dddZedddeedddZdS )ConversationChaina  Chain to have a conversation and load context from memory.

    This class is deprecated in favor of ``RunnableWithMessageHistory``. Please refer
    to this tutorial for more detail: https://python.langchain.com/v0.2/docs/tutorials/chatbot/

    ``RunnableWithMessageHistory`` offers several benefits, including:

    - Stream, batch, and async support;
    - More flexible memory handling, including the ability to manage memory
      outside the chain;
    - Support for multiple threads.

    Below is a minimal implementation, analogous to using ``ConversationChain`` with
    the default ``ConversationBufferMemory``:

        .. code-block:: python

            from langchain_core.chat_history import InMemoryChatMessageHistory
            from langchain_core.runnables.history import RunnableWithMessageHistory
            from langchain_openai import ChatOpenAI


            store = {}  # memory is maintained outside the chain

            def get_session_history(session_id: str) -> InMemoryChatMessageHistory:
                if session_id not in store:
                    store[session_id] = InMemoryChatMessageHistory()
                return store[session_id]

            llm = ChatOpenAI(model="gpt-3.5-turbo-0125")

            chain = RunnableWithMessageHistory(llm, get_session_history)
            chain.invoke(
                "Hi I'm Bob.",
                config={"configurable": {"session_id": "1"}},
            )  # session_id determines thread
    Memory objects can also be incorporated into the ``get_session_history`` callable:

        .. code-block:: python

            from langchain.memory import ConversationBufferWindowMemory
            from langchain_core.chat_history import InMemoryChatMessageHistory
            from langchain_core.runnables.history import RunnableWithMessageHistory
            from langchain_openai import ChatOpenAI


            store = {}  # memory is maintained outside the chain

            def get_session_history(session_id: str) -> InMemoryChatMessageHistory:
                if session_id not in store:
                    store[session_id] = InMemoryChatMessageHistory()
                    return store[session_id]

                memory = ConversationBufferWindowMemory(
                    chat_memory=store[session_id],
                    k=3,
                    return_messages=True,
                )
                assert len(memory.memory_variables) == 1
                key = memory.memory_variables[0]
                messages = memory.load_memory_variables({})[key]
                store[session_id] = InMemoryChatMessageHistory(messages=messages)
                return store[session_id]

            llm = ChatOpenAI(model="gpt-3.5-turbo-0125")

            chain = RunnableWithMessageHistory(llm, get_session_history)
            chain.invoke(
                "Hi I'm Bob.",
                config={"configurable": {"session_id": "1"}},
            )  # session_id determines thread

    Example:
        .. code-block:: python

            from langchain.chains import ConversationChain
            from langchain_community.llms import OpenAI

            conversation = ConversationChain(llm=OpenAI())
    )default_factorymemorypromptinput	input_keyresponse
output_keyc                   @   s   e Zd ZdZdZdS )zConversationChain.ConfigTZforbidN)__name__
__module____qualname__Zarbitrary_types_allowedextra r   r   F/tmp/pip-unpacked-wheel-bo69hh5q/langchain/chains/conversation/base.pyConfigq   s   r   )returnc                 C   s   dS )NFr   )clsr   r   r   is_lc_serializableu   s    z$ConversationChain.is_lc_serializablec                 C   s   | j gS )z5Use this since so some prompt vars come from history.)r   )selfr   r   r   
input_keysy   s    zConversationChain.input_keysFT)preZskip_on_failure)valuesr   c                 C   st   |d j }|d }||kr0td| d| d|d j}||g }t|t|krptd| d| d	| d
|S )z4Validate that prompt input variables are consistent.r   r   zThe input key z$ was also found in the memory keys (z+) - please provide keys that don't overlap.r   z:Got unexpected prompt input variables. The prompt expects z
, but got z as inputs from memory, and z as the normal input key.)Zmemory_variables
ValueErrorZinput_variablesset)r   r"   Zmemory_keysr   Zprompt_variablesZexpected_keysr   r   r   validate_prompt_input_variables~   s    


z1ConversationChain.validate_prompt_input_variablesN)r   r   r   __doc__r   r   r   r   __annotations__r	   r   r   r   strr   r   classmethodboolr   propertyr   r    r   r   r%   r   r   r   r   r      s   
	Q
r   N)r&   typingr   r   Zlangchain_core._apir   Zlangchain_core.memoryr   Zlangchain_core.promptsr   Zlangchain_core.pydantic_v1r   r   Z$langchain.chains.conversation.promptr	   Zlangchain.chains.llmr
   Zlangchain.memory.bufferr   r   r   r   r   r   <module>   s   