MessagesState and chat history

LangGraph · Essentials · 9 min

Chat agents need a message list that appends, updates by ID and accepts plain dicts.

Chat applications keep a list of messages (system, user, assistant, tool). LangGraph ships a reducer made for that list: add_messages.

class State(TypedDict):
    messages: Annotated[list, add_messages]

Compared with operator.add, add_messages:

  • appends new messages,
  • replaces a message when the update has the same message ID, so you can edit one in place,
  • converts plain dicts like {"role": "user", "content": "hi"} into LangChain message objects (HumanMessage, AIMessage, ...).

Because this is so common there is a ready-made state class, MessagesState, with exactly one key, messages, using add_messages. Use it directly, or subclass it to add your own keys:

class State(MessagesState):
    user_name: str

A node that talks to a model typically returns {"messages": [reply]}: a list with only the new message, which gets appended.

To delete old messages (for example to keep the context window small), return RemoveMessage(id=...) objects for the messages to drop; add_messages removes them.

Example

from langchain_core.messages import AIMessage
from langgraph.graph import StateGraph, START, END, MessagesState


class State(MessagesState):        # messages: Annotated[list, add_messages]
    turns: int


def echo(state: State) -> dict:
    last = state["messages"][-1].content
    return {"messages": [AIMessage(f"You said: {last}")], "turns": state.get("turns", 0) + 1}


b = StateGraph(State)
b.add_node(echo)
b.add_edge(START, "echo")
b.add_edge("echo", END)
out = b.compile().invoke({"messages": [{"role": "user", "content": "hi"}]})

for m in out["messages"]:
    print(type(m).__name__, m.content)
# HumanMessage hi
# AIMessage You said: hi

Remember

  • add_messages appends, updates by ID, and converts dicts to message objects
  • MessagesState = a state with a messages key using add_messages
  • Subclass MessagesState to add your own keys
  • Return only new messages; RemoveMessage deletes old ones

Check yourself

  1. A node returns a message whose ID matches one already in state['messages']. With add_messages, what happens?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.langchain.com/oss/python/langgraph/graph-api