# How to manage conversation history in a ReAct Agent

!!! info "Prerequisites"
    This guide assumes familiarity with the following:

    - <a href="../create-react-agent">Prebuilt create_react_agent</a>
    - <a href="../../concepts/persistence">Persistence</a>
    - <a href="../../concepts/memory/#short-term-memory">Short-term Memory</a>
    - [Trimming Messages](https://python.langchain.com/docs/how_to/trim_messages/)

Message history can grow quickly and exceed LLM context window size, whether you're building chatbots with many conversation turns or agentic systems with numerous tool calls. There are several strategies for managing the message history:

* <a href="#keep-the-original-message-history-unmodified">message trimming</a> — remove first or last N messages in the history
* <a href="#summarizing-message-history">summarization</a> — summarize earlier messages in the history and replace them with a summary
* custom strategies (e.g., message filtering, etc.)

To manage message history in `create_react_agent`, you need to define a `pre_model_hook` function or [runnable](https://python.langchain.com/docs/concepts/runnables/) that takes graph state an returns a state update:


* Trimming example:
    ```python hl_lines="1 2 3 4 19 25"
    from langchain_core.messages.utils import (
        trim_messages, 
        count_tokens_approximately
    )
    from langgraph.prebuilt import create_react_agent
    
    # This function will be called every time before the node that calls LLM
    def pre_model_hook(state):
        trimmed_messages = trim_messages(
            state["messages"],
            strategy="last",
            token_counter=count_tokens_approximately,
            max_tokens=384,
            start_on="human",
            end_on=("human", "tool"),
        )
        # You can return updated messages either under `llm_input_messages` or 
        # `messages` key (see the note below)
        return {"llm_input_messages": trimmed_messages}

    checkpointer = InMemorySaver()
    agent = create_react_agent(
        model,
        tools,
        pre_model_hook=pre_model_hook,
        checkpointer=checkpointer,
    )
    ```

* Summarization example:
    ```python hl_lines="1 20 27 28"
    from langmem.short_term import SummarizationNode
    from langchain_core.messages.utils import count_tokens_approximately
    from langgraph.prebuilt.chat_agent_executor import AgentState
    from langgraph.checkpoint.memory import InMemorySaver
    from typing import Any
    
    model = ChatOpenAI(model="gpt-4o")
    
    summarization_node = SummarizationNode(
        token_counter=count_tokens_approximately,
        model=model,
        max_tokens=384,
        max_summary_tokens=128,
        output_messages_key="llm_input_messages",
    )

    class State(AgentState):
        # NOTE: we're adding this key to keep track of previous summary information
        # to make sure we're not summarizing on every LLM call
        context: dict[str, Any]
    
    
    checkpointer = InMemorySaver()
    graph = create_react_agent(
        model,
        tools,
        pre_model_hook=summarization_node,
        state_schema=State,
        checkpointer=checkpointer,
    )
    ```

!!! Important
    
    * To **keep the original message history unmodified** in the graph state and pass the updated history **only as the input to the LLM**, return updated messages under `llm_input_messages` key
    * To **overwrite the original message history** in the graph state with the updated history, return updated messages under `messages` key
    
    To overwrite the `messages` key, you need to do the following:

    ```python
    from langchain_core.messages import RemoveMessage
    from langgraph.graph.message import REMOVE_ALL_MESSAGES

    def pre_model_hook(state):
        updated_messages = ...
        return {
            "messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES), *updated_messages]
            ...
        }
    ```

## Setup

First, let's install the required packages and set our API keys


```shell
pip install -U langgraph langchain-openai langmem
```


```python
import getpass
import os


def _set_env(var: str):
    if not os.environ.get(var):
        os.environ[var] = getpass.getpass(f"{var}: ")


_set_env("OPENAI_API_KEY")
```

<div class="admonition tip">
    <p class="admonition-title">Set up <a href="https://smith.langchain.com">LangSmith</a> for LangGraph development</p>
    <p style="padding-top: 5px;">
        Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started <a href="https://docs.smith.langchain.com">here</a>. 
    </p>
</div>

## Keep the original message history unmodified

Let's build a ReAct agent with a step that manages the conversation history: when the length of the history exceeds a specified number of tokens, we will call [`trim_messages`](https://python.langchain.com/api_reference/core/messages/langchain_core.messages.utils.trim_messages.html) utility that that will reduce the history while satisfying LLM provider constraints.

There are two ways that the updated message history can be applied inside ReAct agent:

  * <a href="#keep-the-original-message-history-unmodified">**Keep the original message history unmodified**</a> in the graph state and pass the updated history **only as the input to the LLM**
  * <a href="#overwrite-the-original-message-history">**Overwrite the original message history**</a> in the graph state with the updated history

Let's start by implementing the first one. We'll need to first define model and tools for our agent:


```python
from langchain_openai import ChatOpenAI

model = ChatOpenAI(model="gpt-4o", temperature=0)


def get_weather(location: str) -> str:
    """Use this to get weather information."""
    if any([city in location.lower() for city in ["nyc", "new york city"]]):
        return "It might be cloudy in nyc, with a chance of rain and temperatures up to 80 degrees."
    elif any([city in location.lower() for city in ["sf", "san francisco"]]):
        return "It's always sunny in sf"
    else:
        return f"I am not sure what the weather is in {location}"


tools = [get_weather]
```

Now let's implement `pre_model_hook` — a function that will be added as a new node and called every time **before** the node that calls the LLM (the `agent` node).

Our implementation will wrap the `trim_messages` call and return the trimmed messages under `llm_input_messages`. This will **keep the original message history unmodified** in the graph state and pass the updated history **only as the input to the LLM**


```python hl_lines="4 5 6 7 22 29"
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import InMemorySaver

from langchain_core.messages.utils import (
    trim_messages,
    count_tokens_approximately,
)