Checkpointer: a thread that keeps its files
A checkpointer is the object that saves a deep agent's whole state, its messages and its files, after every step, under a thread_id, so the next call on the same thread continues where the last one stopped.
Last updated: 29 Sep, 2026 · Deep Agents 0.7
One thread, one set of files
In the context engineering section the video creates agents with checkpointer=MemorySaver() and a thread_id in the config. It explains that with the default state backend, what the agent saves lives in the LangGraph state of that thread: it is there for every call on the same thread, and gone when the agent is closed. The file system backend keeps files on disk, and the store backend keeps them for separate sessions; the next part of the course covers both.
MemorySaver is the older name of InMemorySaver; both import from langgraph.checkpoint.memory and are the same class.
The checkpointer syntax
from langgraph.checkpoint.memory import InMemorySaver
agent = create_deep_agent(model=model, checkpointer=InMemorySaver())
agent.invoke({"messages": [...]}, config={"configurable": {"thread_id": "paris-trip"}})The agent with a checkpointer
Start trip.py with search_travel, the catalog tool from Tools: a travel search the agent can call. Everything below goes in the same file, under it.
from langchain.tools import tool
CATALOG = {
"paris": {
"flight": ["Return flight Delhi to Paris: 42,000 rupees"],
"hotel": ["Seine Budget Inn, Latin Quarter: 5,200 rupees a night",
"Hotel Lumiere, Montmartre: 7,500 rupees a night",
"Le Grand Opera Hotel: 16,000 rupees a night"],
"sight": ["Eiffel Tower summit: 3,100 rupees", "Louvre Museum: 2,000 rupees",
"Seine river cruise: 1,500 rupees", "Versailles day trip: 2,600 rupees",
"Montmartre walking tour: free"],
"food": ["Cafe breakfast and bistro dinner: 3,000 rupees a day"],
},
}
@tool
def search_travel(city: str, kind: str) -> str:
"""Search the travel catalog. kind is "flight", "hotel", "sight" or "food". Prices are in rupees."""
entries = CATALOG.get(city.lower(), {}).get(kind)
return "\n".join(entries) if entries else f"The catalog has no {kind} entries for {city}."from deepagents import create_deep_agent
from langchain.chat_models import init_chat_model
model = init_chat_model("groq:openai/gpt-oss-120b", temperature=0, max_retries=6)from langgraph.checkpoint.memory import InMemorySaver
agent = create_deep_agent(
model=model,
tools=[search_travel],
checkpointer=InMemorySaver(), # saves messages and files after every step
system_prompt="You are a travel planner. Reply in one short sentence.",
)
thread = {"configurable": {"thread_id": "paris-trip"}}A helper that asks on a thread
ask sends one message on a thread and prints the reply.
def ask(text, config):
result = agent.invoke({"messages": [{"role": "user", "content": text}]}, config=config)
print("you: ", text)
print("agent:", result["messages"][-1].text)
return resultEditing a plan across two calls, then a new thread
The run edits a file across two calls on the same thread, then asks for it on a new thread and prints every message of that run.
ask("Write /trip/plan.md with two lines: Day 1: Eiffel Tower. Day 2: Louvre Museum.", thread)
result = ask("Add the Seine river cruise to day 2 of the plan.", thread)
print(result["files"]["/trip/plan.md"]["content"])
result = agent.invoke({"messages": [{"role": "user", "content": "Read /trip/plan.md and tell me what it says."}]},
config={"configurable": {"thread_id": "another-trip"}})
for message in result["messages"]:
print(f"{message.type:<5}", message.text or [(c["name"], c["args"]) for c in message.tool_calls])you: Write /trip/plan.md with two lines: Day 1: Eiffel Tower. Day 2: Louvre Museum.
agent: Plan saved.
you: Add the Seine river cruise to day 2 of the plan.
agent: Day 2 now includes the Seine river cruise.
Day 1: Eiffel Tower.
Day 2: Louvre Museum, Seine river cruise.
human Read /trip/plan.md and tell me what it says.
ai [('read_file', {'file_path': '/trip/plan.md'})]
tool Error: File '/trip/plan.md' not found
ai [('ls', {'path': '/trip'})]
tool No files found
ai [('glob', {'path': '/', 'pattern': '*.md'})]
tool No files found
ai [('glob', {'path': '/', 'pattern': '**/*.md'})]
tool No files found
ai The file /trip/plan.md doesn’t exist in the current system.What the three calls show
- Call one wrote
/trip/plan.md. Nothing was passed back by hand. - Call two sent only the new message. The checkpointer restored the thread's state, so the agent found the file and updated day 2; the printed file shows the cruise added.
- The new thread started empty:
read_fileanswered that the file was not found,lsandglobfound no files at all, and the agent said the file does not exist. Files inStateBackendbelong to one thread.
InMemorySaver vs a saver on disk
| Checkpointer | Survives a restart | Package |
|---|---|---|
InMemorySaver | No, it lives in the Python process | langgraph (installed) |
SqliteSaver | Yes, a SQLite file | langgraph-checkpoint-sqlite |
PostgresSaver | Yes, a database | langgraph-checkpoint-postgres |
Integrations: taking the trip planner to production swaps in SqliteSaver and shows a thread surviving a new agent.
Where a checkpointer is needed
- Any chat: every turn continues the same conversation and files.
- Pausing for a person, which Human-in-the-loop: approving a booking needs: the paused state has to be saved somewhere.
- Long tasks you may resume after an error.
thread_id is the key to everything. Reuse one by mistake and a new traveller sees the last traveller's plan; make a fresh one each time and the agent never remembers anything.Related
- Previous: Virtual filesystem: files in the agent's state
- Next: Context offloading: large results saved to files
- Reference: LangGraph persistence
- Ask a third question on
paris-trip: "Move the Louvre to day 1." and print the file. - Print
agent.get_state(thread).values["files"]to read the thread's files without a model call. - Run the new-thread question with
thread_idparis-tripinstead and compare.
This is what real progress feels like.