WHAT YOU WILL BUILD
A small memory lookup with identity, version, and expiration boundaries.
Memory is stored information retrieved under a policy. This example chooses the latest unexpired value for one user and key. It makes updates and expiration visible without implying that a model remembers data outside the supplied context.
Before you start
Use a text editor and Node.js 22 or newer ↗. Check your version with node --version. Save the downloaded file in an empty folder, then open a terminal in that folder.
All data is included. No packages, account, or API key are required. Records live in a local array and times are arbitrary teaching units. This is not persistent storage or an authentication system.
Download the lab (.mjs)FOLLOW ALONG
Work through the example.
- 01
Inspect the three records
Alex has an older English preference and a newer French preference. Blair has a Spanish preference with an even higher version. The user filter must happen before selecting the latest value.
- 02
Recall at time twelve
Run the example. Alex receives French. The higher version belonging to Blair cannot override Alex's preference.
- 03
Recall after expiration
At time twenty-one, both Alex records have expired and the lookup returns null. The application should ask again or use a stated default; it must not borrow another user's record.
- 04
Test a correction
Add Alex's version-three preference with a later expiry. Update your expected answer and verify the correction wins. Add a deletion test before adapting this to persistent storage.
THE COMPLETE LAB
Run it locally.
Run this command from the folder containing your downloaded file:
node agent-memory.mjsView or copy the complete JavaScript
// SaveMyToken local lab. Run with Node.js 22 or newer.
import assert from "node:assert/strict";
const records = [
{ user: "alex", key: "language", value: "English", version: 1, expires: 10 },
{ user: "alex", key: "language", value: "French", version: 2, expires: 20 },
{ user: "blair", key: "language", value: "Spanish", version: 3, expires: 30 },
];
function recall(user, key, now) {
return records.filter(row => row.user === user && row.key === key && row.expires > now)
.sort((a, b) => b.version - a.version)[0]?.value ?? null;
}
assert.equal(recall("alex", "language", 12), "French");
assert.equal(recall("alex", "language", 21), null);
assert.equal(recall("unknown", "language", 12), null);
console.log("Alex at t=12:", recall("alex", "language", 12));
console.log("Alex at t=21:", recall("alex", "language", 21));
Expected output for the unchanged example
Alex at t=12: French
Alex at t=21: nullThe assertions also check the baseline behavior. After changing an input, predict the result and update the relevant assertion.
NOW CHANGE ONE THING
Make the example your own.
Introduce two memory keys for Alex. Verify that updating language does not change a project preference, and that an unknown user always receives null.
You are done when…
Version selection, expiration, key selection, and user isolation each have an independent test.
If something goes wrong
In a real service, derive the user identity from authenticated server context. This example accepts a string only to make the lookup rule easy to inspect.
EXPLAIN WHAT YOU LEARNED
Interview practice
Try answering aloud before opening the reference answer. These are original learning questions, not a record of any employer's interviews.
01How does stored memory differ from conversation history?
History records a sequence of messages. Memory selects information intended to remain useful and retrieves it under explicit scope and update rules.
Watch for: Saving every message indefinitely does not make memory reliable.
02What makes a memory record maintainable?
Keep its scope, origin, update or version information, and any expiration or deletion rule. Store enough provenance to resolve conflicts or correct a mistaken value.
Watch for: A bare sentence loses who it applies to and whether it is still current.
03How should conflicting preferences be resolved?
Use a documented precedence rule that respects scope and explicit corrections. If the intended value remains uncertain, ask rather than silently combining incompatible preferences.
Watch for: The most recently retrieved record is not always the authoritative one.
04Where should user isolation be enforced?
At the storage and retrieval boundary using authenticated identity and resource authorization. Test that unrelated records cannot enter the returned context.
Watch for: Asking the model to ignore another user's data is too late once that data was retrieved.
05How do you evaluate a memory system?
Test retention of relevant facts, successful corrections, expiration, deletion, and cross-user isolation. Also check whether retrieved memories help the current task.
Watch for: A higher recall rate can be harmful if it brings back stale or irrelevant data.
Sources and further reading
The explanation and local exercises were written for SaveMyToken. These references support the underlying concepts; the sample outputs describe only the supplied examples.
LangChain: short-term memory ↗