ai
Agent Memory Store
One conversation log, read two ways: by recency and by meaning.
An assistant needs the last few messages every turn, and occasionally the one thing said three weeks ago that bears on the question. Those are different reads over the same items. The recency window is a Query on the session; relevance is a vector search partitioned by USER, which is what lets it reach back past the conversation you are already in.
The model
Message
One message in one session, with the vector of its text.
- pk
- SESSION#<sessionId>
- sk
- TS#<sentAtIso>
Attributes: userId (S), text (S), embedding (L)
Access patterns
- QueryRecent messages in a session
The last few turns of the conversation that is open now.
- SearchVectors · by-userRelevant messages for a user
Messages near a topic, across every session that user has had.
Design notes
Partitioned by user, not by sessionmodelling
The SearchSchema declares userId as its HASH. Partition by session instead and relevance can only ever reach inside the conversation you are already in, which is the one place the recency Query has already covered. Partitioning by user is what makes the second read path worth having.
The HASH is not a security boundarysecurity
Fine-grained access control does not apply to SearchVectors, so any principal holding dynamodb:SearchVectors on this index can search any user's partition by changing one string. Real isolation needs separate tables or indexes with separate IAM grants. A per-user partition key is a data-locality mechanism, not a permission.
Four dimensions here, hundreds in productionmodelling
These vectors are hand-authored at four dimensions so the values are readable on the page. A real embedding model emits 384 or more. Nothing about the index changes with dimensionality: it is fixed at creation, it is the only thing the index validates, and it is the only reason a query from the wrong model is ever refused.
Taught in the course
- One query, a whole collection - Items that share a partition key are read together in one Query.
These rows are real and already here. Running an operation against them downloads a DynamoDB-compatible engine, about 850 KB, and executes it in this tab.
The last few turns of the conversation that is open now.
Run an operation to see the raw engine response.
Transactions, streams, tags and TTL are among the operations the in-browser engine doesn't implement yet.