thread_id and resume

Up to this point, every turn started from whatever you passed in. Close the shell, lose the state. MemorySaver fixes that. It is a LangGraph checkpointer that snapshots the state after every node run, keyed on a configurable thread_id. The next invoke resumes from the last checkpoint.

booking_graph.py
python
from langgraph.checkpoint.memory import MemorySaver

def build_graph():
    graph = StateGraph(BookingState)
    # ... add_node and add_edge calls ...

    checkpointer = MemorySaver()
    return graph.compile(checkpointer=checkpointer)

One line wires persistence in. MemorySaver is in-memory and perfect for development. For production, swap it with a Postgres or Redis checkpointer without changing anything else in the graph.

service.py
python
async def chat(self, thread_id: str, user_message: str) -> Dict[str, Any]:
    """Run one turn through the graph. MemorySaver resumes prior state."""
    config = {"configurable": {"thread_id": thread_id}}

    turn_input: Dict[str, Any] = {
        "user_message": user_message,
        "thread_id": thread_id,
    }
    prior = self._graph.get_state(config)
    prior_messages = []
    if prior and prior.values:
        prior_messages = list(prior.values.get("messages") or [])
    prior_messages.append({"role": "user", "content": user_message})
    turn_input["messages"] = prior_messages

    result = await self._graph.ainvoke(turn_input, config=config)

The thread_id goes into configurable, not into the input. That is what tells MemorySaver which saved state to load. Pass the same thread_id again and the graph resumes with every slot, every stage, every message intact.

Resume semantics across turns

Quiz: Quiz

Loading practice…