Chapter 3
How does an agent decide what to remember?
About the write path: how a chat transcript becomes a handful of memories. We will also see the big debate of 2026, whether the extractor should be allowed to update and delete old memories, and why the winning answer is "no".
Before you read, guessHow does an agent determine what to record in its memory?
Take ten seconds and guess — even a wrong guess makes the answer stick. Tap to see where the chapter lands, or just read on.
It writes down what matters, with a date and a name, and it is allowed to say "this replaces that".
In this blog, we will learn about the write path: how a chat transcript becomes a handful of memories. We will also see the big debate of 2026, whether the extractor should be allowed to update and delete old memories, and why the winning answer is "no".
The secretary taking minutes
Imagine a meeting with a secretary in the corner. The secretary does not write down every word. They write the decisions and the facts worth remembering next week. "Maya moved to Paris." "Sam's birthday is June 18." Not "Maya complained about Mondays."
That secretary is a small LLM call, run once per session, at temperature 0, returning strict JSON. It reads about 1,500 tokens and writes back about three facts of 25 tokens each.
transcript ~1,500 tok ---> extractor LLM ---> [ {fact, category}, ... ]
|
+--- dropped: small talk, jokes, weather,
one-off requests ("rephrase this email")
The class experiment is a good picture. A 14-message session with a move, a diet, a birthday, and a style instruction mixed with four bits of ephemera came out as 4 facts and 39 tokens. All four ephemera were dropped.
Write once, read forever
Extraction costs one call. The facts are then read on every future session. Over 100 sessions, replaying the transcript costs 22,100 prompt tokens; injecting the facts costs 3,900. So we shape what we store for the read path, and we never make the user wait for the write.
answer call ----> user sees the reply
|
+---> background: extract, embed, store (seconds are fine)
The async-write experiment shows the user-perceived latency dropping by more than half simply by moving extraction off the critical path.
The consolidation problem
Now the hard part. A new fact arrives: "Maya moved from London to Paris." The store already says "Maya lives in London." What do we do?
The classic answer, from the Mem0 paper and the class notes, is a second LLM call per fact. Retrieve the most similar stored memories, show them to the model, and let it pick one operation:
candidate op target
"Maya moved from London to Paris last month." UPDATE "lives in London"
"Maya is vegetarian." NOOP exact duplicate
"Maya adopted a cat named Miso." ADD new row
"Maya no longer trains for the marathon." UPDATE marathon row
This works, and the update-or-add experiment shows it working: 4 candidates, 5 true memories at the end instead of 8 stacked contradictions.
Why Mem0 stopped updating and deleting
In April 2026 Mem0 rewrote its algorithm. The headline change was ADD-only extraction: one LLM call, no UPDATE, no DELETE. Their LoCoMo score went from 71 to 92. Three things happened at once:
- Nothing is destroyed. An UPDATE that rewrites "lives in London" into "lives in Paris" makes "where did I use to live?" unanswerable. Keeping both, with dates, answers both questions.
- Fewer calls. One extraction call instead of one plus one per fact. Extraction got about 2x faster.
- Dedup moved into the prompt. The extractor is shown the 10 most similar existing memories and told to skip anything already captured and to link new memories to related old ones. It still cannot delete.
The new memories are also richer. Instead of "User prefers oat milk" the prompt asks for "User switched from almond milk to oat milk lattes after developing an almond sensitivity". The transition is the memory.
What HydraDB adds: time stamps instead of deletes
HydraDB and Zep describe the same instinct with a database word: append-only. Every fact is a versioned row. A new fact that replaces an old one does not overwrite it; it closes the old one's validity window.
"Maya lives in London." valid_from 2025-01 valid_to 2026-03 superseded_by #7
"Maya lives in Paris." valid_from 2026-03 valid_to NULL (#7)
Ask "where does Maya live?" and you get the open row. Ask "where did she live before?" and you get the closed one. Nobody deleted anything, and the store still stays true. The next blog is all about this.
The hybrid write path
Putting it together, our extractor does one call and returns, per fact:
{ "text": "...15 to 80 words, names not pronouns, absolute dates...",
"category": "semantic | episodic | procedural",
"importance": 1..10,
"event_date": "2026-03-01" or null,
"entities": ["Maya", "Paris"],
"links": ["id of a related existing memory"],
"supersedes": ["id of an existing memory this replaces"] }
Then, without any more LLM calls: drop exact duplicates by hash, drop near duplicates by cosine similarity above 0.95, embed the rest in one batch, insert, link entities, and stamp valid_to on anything superseded.
Closing
The write path is a secretary, not a censor. It writes down what matters, with a date and a name, and it is allowed to say "this replaces that". It is never allowed to tear a page out. That single rule is worth twenty benchmark points.