Agents need memory beyond one context window:
| Tier | Holds | Lifetime | Backed by | | --- | --- | --- | --- | | Scratchpad | current message list | one run | in-process array | | Episodic summary | compressed history of the run | run or session | model-generated summary | | Long-term | durable facts and preferences | forever | database + vector search |
Compress the scratchpad when it approaches a token threshold instead of truncating blindly:
ts
async function compress(messages: Msg[], limit = 12_000) {
if (countTokens(messages) < limit) return messages;
const [system, ...rest] = messages;
const head = rest.slice(0, -6); // keep the last 6 turns verbatim
const summary = await chatOnce(
"Summarise the facts, decisions and open questions below in under 200 words.",
head,
);
return [system, { role: "assistant" as const, content: "Context so far: " + summary }, ...rest.slice(-6)];
}Long-term memory should store facts, not transcripts: `user prefers metric units` retrieves far better than a 40-turn conversation. Write facts through an explicit `remember` tool so the agent's memory is auditable and deletable — a requirement for GDPR-style deletion requests.
Exercise: add `remember(fact)` and `recall(query)` tools backed by a table with a vector column, then verify a preference stated in session one is applied in session two.