Memory, state and multi-step plans
A model remembers nothing between calls, yet Ama wants an assistant that can work on one problem for a whole morning, wait two hours for her approval and survive a deploy in the middle. This lesson shows you where an agent's memory really lives, how to build each step's context so the model keeps the thread, and how to store plans in Postgres so a task can stop and resume safely.
By the end you can
- Name the four kinds of agent memory and put each fact in the right one
- Build a step's context from the plan, a compacted state note and only the newest tool results
- Store a plan as data with step statuses, and re-plan when a step fails
- Save tasks and steps in Postgres so a crash, a deploy or a long approval wait does not lose the thread, and resume without doing a write twice
- Decide what long-term memory may hold, how it expires, and how the user sees and deletes it
The everyday picture
Picture a store office where a different temporary worker arrives every hour. Each one is smart and fast, but has never seen the job before and remembers nothing from earlier visits. The only thing that carries the work from hour to hour is the folder on the desk.
A good folder has a job sheet on top: the goal, a numbered list of steps, and a tick, a cross or "waiting for signature" next to each one. Under it sit the last two receipts in full, then a one-page cover note that sums up everything older, with every order number copied exactly. A bad folder is a 400-page pile of every receipt ever printed. The temp spends the hour reading, misses the one page in the middle that mattered, and forgets what the job was. And if the folder lives in a locked cabinet instead of on the desk, a power cut or a fire drill loses nothing: the next temp opens the cabinet and carries on. That folder, kept in that cabinet, is what this lesson builds.
The model remembers nothing: four kinds of memory
You saw in the first LLM apps lesson that a model API is stateless: every call starts from zero, and a chat only feels continuous because your code resends the history each turn. An agent is the same loop with tools (What makes an agent). So everything the model "knows" during a step is exactly what you put into that step's request. If a fact is not in the request, the model does not have it, however many times it saw it before.
That makes memory a design job for your code. It helps to split it into four kinds, because each one has a different home and a different lifetime:
| Kind | What it holds | Where it lives | Lifetime |
|---|---|---|---|
| Working context | The prompt for this one step | The request you send | One call |
| Task trace | Every model reply, tool call and tool result in this task | A table, written as it happens | The task, then kept for audit |
| Durable task state | The goal, the plan, each step's status, inputs and outputs | Postgres rows | Until the task ends |
| Long-term memory | Facts about the user or store that help next time | Its own table, with expiry | Weeks or months |
The trap is to treat the first kind as if it were the other three. A prototype keeps the whole conversation in a JavaScript array in the server's memory and sends all of it every step. That works for a two-minute demo. It fails when the task is long (the array becomes huge), when the server restarts (the array is gone) and when the task waits for a person (a process sits idle for hours holding it). The rest of this lesson moves each kind of memory to its proper home.
Quick check
The agent has finished four steps and is waiting for Ama to approve step 5. Where must the fact "step 5 is waiting for approval" live?
The wait may last hours and survive restarts, so it belongs in a database row that your runner reads. You will also copy it into the next step's context, but the context is rebuilt each time from the row. Long-term memory is for facts that outlive the task, and the model itself keeps nothing between calls.