PHASE 08 · MEMORY

Agents that remember

Goal: Move from stateless chat to persistent, personalized interactions.

What this is

An LLM call is stateless — the model forgets everything between requests. Memory is the system you build around the model to make it feel persistent.

There are two tiers. Short-term memory is the conversation history within a single session: you store messages in a list, pass the last N turns into each new prompt. Long-term memory is facts about the user that survive across sessions: their name, preferences, past projects, recurring topics. Stored in SQLite or a vector DB keyed by user_id, loaded into the system prompt at session start.

The third concept is identity: the user profile + persistent system prompt that makes "this agent" feel like this agent. And as conversations grow long, you'll need compaction: replace old turns with a summary so you don't blow the context window.

The plan

  1. Short-term: store messages in-memory keyed by session_id. Pass the last N turns into each new prompt.
  2. Long-term: at session end, call an LLM to extract durable facts ("user lives in Atlanta", "works on agentic AI at AWS"). Store them in SQLite, tagged by user_id and timestamp.
  3. On new session start: load the user's facts + a summary of their most recent session into the system prompt. The agent now picks up where it left off.
  4. Add a vector store over old conversation summaries — when a question relates to past topics, retrieve and inject them (long-term recall, not just last session).
  5. Handle context limits with compaction: when a session exceeds N tokens, summarize the oldest M turns and replace them with the summary.

Ask your coding assistant

  • How does ChatGPT 'remember' me between sessions? What's actually stored?
  • Compare Mem0, Letta (formerly MemGPT), and LangChain's memory modules — what's the right tool for me?
  • What is context-window management and why does it matter?
  • Strategies for conversation summarization without losing key facts.
  • How do I extract user facts from a conversation reliably?

What you'll have when you're done

  • Your agent remembers you across sessions and references past chats.
  • Long conversations don't blow up the context window.
  • You can build a personalized assistant, not a stateless chatbot.
  • You understand the recall vs. cost tradeoff — more memory = bigger, slower, costlier prompts.

Deliverable

memory.py — The agent remembers across sessions, summarizes long chats, and personalizes replies.

Concepts unlocked: memory tiers · compaction · user modeling · identity

Intuition

Back in Phase 1 you learned the most jarring fact in this course: the model remembers nothing between calls. Every single API call starts from a blank slate, and the "conversation" is an illusion your code creates by re-sending the whole transcript every time. So how does a chatbot greet you by name, or pick up a project you mentioned last week? It doesn't. You build the memory around it, and feed the right bits back in each time.

Here's the analogy that carries this whole phase. Imagine a brilliant assistant with total amnesia — sharp as anyone while you're talking, but the moment a conversation ends, it's gone. Their fix: a notebook. Before every reply, they re-read their notes. After every conversation, they jot down what mattered. Ask them next week and they answer instantly — not because they remember, but because they read it back to themselves a second ago. That notebook is what "memory" means for an agent: text it saves, then re-loads into the prompt.

One word to pin down before the example: a session is one continuous conversation — from the moment you open the chat to the moment you close it. Within a session, your code holds the growing message list. Between sessions, only what got written to the notebook survives.

What memory really is. The model is stateless — nothing carries over between calls. "Memory" is the notebook system you build around it: well-chosen text, saved after conversations and loaded back into the prompt. The skill of this phase is choosing what to write down and what to read back.

Two tiers

So the agent keeps a notebook. That notebook has two distinct parts — the page it's writing on right now, and the saved notes in the back. In agent terms, memory comes in two tiers:

  • Short-term — the conversation within one session. This is just Phase 1's growing message list: you keep the messages and pass the last few turns into each new prompt. That's how the agent follows the thread of this chat. Nothing new to build — you've had this since Phase 1.
  • Long-term — everything that should survive across sessions. Two kinds of notes live here. Saved facts: short, durable truths about the user — for Zentara's customer Maya, things like "prefers email over phone" and "manages the Atlanta warehouse." And session summaries: a few-sentence recap written at the end of each conversation — "last week we set up their refund workflow." Both get saved (a small database works fine — or the vector database from Phase 2, if you want to search memories by meaning) and loaded into the system prompt when a new session starts.

Why both kinds? They answer different questions. A saved fact answers "who is this person?" — true today, true next month. A session summary answers "what were we doing?" — the story so far, one chapter per conversation. An agent that loads only facts knows Maya but forgets the project; one that loads only summaries knows the project but keeps asking how she'd like to be contacted.

"Loaded into the system prompt" is a bit abstract — here's what it literally means. This is the actual text sent to the model, assembled from both tiers, before Maya's new question is even added:

You are Zentara Logistics' support agent, talking to Maya.

Known facts (long-term):
- Prefers email over phone
- Manages the Atlanta warehouse

Last session summary (long-term):
- Set up her refund workflow: refunds under $50
  auto-approve, larger ones go to a human.
  She wants to add email notifications next.

Recent messages (short-term, this session):
- user: "can we pick up where we left off?"
- assistant: "Sure — ready to add those email
  notifications to the refund workflow?"

That's the whole trick, in full: just text, assembled from the notebook, pasted in front of the conversation. Nothing about the model changed — it's still the amnesiac from Phase 1. You just handed it the right reminders before it started predicting.

The whole trick behind "it remembers me". At the start of a new session, load the user's saved facts and a short summary of last time into the system prompt. The agent picks up right where it left off — without remembering a thing.

When chats get long

Short-term memory has a catch. Remember from Phase 1 that the whole transcript is re-sent on every call — and the model can only read so much at once. That limit is its context window: the maximum amount of text one call can hold. A busy support chat can run to hundreds of turns; eventually the transcript simply won't fit. And even before it stops fitting, it hurts — every extra turn is re-sent (and paid for) on every single call.

The fix is compaction. Think of the notebook again: when the page fills up, you don't copy every old line onto a fresh page — you write one condensed note at the top ("so far we've…") and keep going. Compaction does exactly that to a chat: summarize the oldest turns into a few sentences, replace them with that summary, and keep the recent turns word-for-word. You trade exact wording for room.

Watch it happen — messages fill the window, and the oldest ones squeeze into a single summary card:

Before and after — what compaction actually does

Here's a real Zentara support session, six messages in and pushing the limit:

1  user:      "A customer on order #4127 wants a refund —
              the item arrived damaged."
2  assistant: "Got it. Order #4127 is $38, under the $50
              auto-approve limit. Refund issued."
3  user:      "She asked if we can send a replacement
              instead next time."
4  assistant: "Noted — I've marked replacement-first as
              her preference."
5  user:      "New topic: what's our policy on late
              international shipments?"
6  assistant: "Zentara refunds shipping fees on international
              orders that arrive more than 10 days late."

Compaction asks the model to summarize the oldest four messages, then swaps them out. This is what the list looks like afterwards:

★  [summary of msgs 1–4]:
   "Issued a $38 auto-approved refund for damaged
   order #4127. Customer prefers a replacement over
   a refund in future cases."

5  user:      "New topic: what's our policy on late
              international shipments?"
6  assistant: "Zentara refunds shipping fees on international
              orders that arrive more than 10 days late."

Look at what survived and what didn't. The facts made it: the order number, the $38, the replacement preference — if message 7 asks "what did we refund on #4127?", the agent can still answer. The exact wording is gone. And the two most recent turns stayed untouched, word-for-word, because the current thread is where precision matters most.

Compaction is lossy. Whatever the summary drops, the agent has truly forgotten — there's no original to go back to inside the chat. That's why compaction targets the oldest turns and keeps recent ones verbatim: the further back a detail is, the less likely you need its exact wording.

And here's the neat part: long-term memory is built with the very same move. At the end of a session, you ask the model to write the session summary (compaction's trick, applied to the whole chat) and to pull out durable facts ("prefers email over phone") to save. One habit, two payoffs: summarize to remember; extract to personalize.

Compaction in one line. Compaction = replace the oldest turns of a long chat with a short model-written summary, so the conversation keeps fitting in the context window. The gist stays; the space comes back.

Build memory

Time to give your agent its notebook: short-term within a session, long-term across sessions, and compaction for chats that run long.

Read what it builds — the notebook routine in code: memory loaded into the prompt at the start of a session, written back at the end:

# memory.py — make a stateless model feel persistent
def build_prompt(user_id, session_id, question):
    facts  = load_facts(user_id)            # long-term: saved facts
    summary = last_summary(user_id)         # long-term: last session's recap
    recent = last_turns(session_id, n=8)    # short-term: this session
    system = f"You are talking to {facts}. Last time: {summary}"
    if too_long(recent):
        recent = compact(recent)            # summarize oldest turns to fit
    return system, recent + [{"role": "user", "content": question}]

def end_session(user_id, session_id):
    facts = extract_facts(history(session_id))   # ask the model what to remember
    save_facts(user_id, facts)
    save_summary(user_id, summarize(history(session_id)))
Deliverable — memory.py. The agent remembers across sessions, compacts long chats so they fit, and personalizes its replies — built entirely from saving and re-loading text around a model that still remembers nothing.