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.
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.
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…