Memory that outlives the conversation
A thread holds one conversation. A store holds facts that last across all of them, saved as JSON documents filed under a namespace and a key.
Ravi told the shop once to leave parcels at the back door. That belongs to Ravi, not to any one conversation, so a new thread next week should still know it.
Putting and getting
from langgraph.store.memory import InMemoryStore
store = InMemoryStore()
store.put(("customers", "ravi"), "delivery", {"note": "leave it at the back door"})
item = store.get(("customers", "ravi"), "delivery")
print(item.key, item.value)
print(store.get(("customers", "mei"), "delivery"))The namespace is a tuple that works like a folder path, here one folder per customer. The key names a document in it, and the value is a dictionary. Asking for a document that is not there returns None.
Pick one to watch it run, step by step.
A tool with the store
from dataclasses import dataclass
@dataclass
class Customer:
name: str
from langchain.tools import ToolRuntime, tool
ORDERS = {"A17": "shipped on 3 March", "C40": "waiting for stock"}
@tool
def lookup_order(order_id: str, runtime: ToolRuntime[Customer]) -> str:
"""Look up an order's shipping status by its id, such as A17."""
folder = ("customers", runtime.context.name)
runtime.store.put(folder, "last_order", {"order_id": order_id})
note = runtime.store.get(folder, "delivery")
status = f"{order_id} {ORDERS.get(order_id, 'is not an order we have')}."
return f"{status} Delivery note: {note.value['note']}." if note else statusruntime.store is the store the agent was given. The tool reads Ravi's delivery note into its answer, and writes which order he asked about last. The agent gets the store, the context from lesson 9 and a checkpointer.
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.store.memory import InMemoryStore
from shop_model import ShopModel
from tools import Customer, lookup_order
store = InMemoryStore()
store.put(("customers", "ravi"), "delivery", {"note": "leave it at the back door"})
agent = create_agent(ShopModel(), tools=[lookup_order], context_schema=Customer,
checkpointer=InMemorySaver(), store=store)ravi = Customer("ravi")
result = agent.invoke({"messages": [{"role": "user", "content": "Where is A17?"}]},
{"configurable": {"thread_id": "monday"}}, context=ravi)
print(result["messages"][-1].text)The delivery note came out of the store, not out of the conversation, and the tool wrote A17 down as the order Ravi asked about last.
A new thread, the same customer
result = agent.invoke({"messages": [{"role": "user", "content": "And C40?"}]},
{"configurable": {"thread_id": "friday"}}, context=ravi)
print(len(result["messages"]))
print(store.get(("customers", "ravi"), "last_order").value)The Friday thread starts with four messages, none from Monday: the checkpointer keeps threads apart. The store does not. It still has Ravi's note, and the last order is now C40, written during Friday's call.
- Invoke as Mei and check that the answer has no delivery note.
- Print
[i.key for i in store.search(("customers", "ravi"))]. - Create the agent without
store=and read the error the tool raises.
This is what real progress feels like.