Skip to content
← All patterns

ai

Agent Memory Store

What should this agent remember?

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, and a different number everywhere elsemodelling

These vectors are hand-authored at four dimensions so the values are readable on the page. A sentence encoder emits 384 or more; the projected coordinates in Geospatial Nearest Neighbour are three, and they are production numbers rather than illustrative ones. 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 built in the wrong space is ever refused.

Taught in the course

agent-memoryDynamoDB workbench
Ready to run
Explore an access patternSelect to load & run

The last few turns of the conversation that is open now.

Request
Execute against the local Dynoxide engine
ReturnedFiltered outChanged
PK(pk)
SK(sk)
embedding
text
userId
SESSION#s-101
TS#2026-08-27T00:00:00ZS
[0.91, 0.12, 0.05, 0.03]L
Roll the API out to Kubernetes rather than the VM fleetS
u-adaS
SESSION#s-101
TS#2026-08-27T02:24:00ZS
[0.88, 0.19, 0.07, 0.02]L
The rollout needs a readiness probe or traffic hits pods that are not upS
u-adaS
SESSION#s-102
TS#2026-09-10T00:00:00ZS
[0.08, 0.94, 0.11, 0.04]L
Invoice totals are off by a penny on multi-currency accountsS
u-adaS
SESSION#s-103
TS#2026-09-21T00:00:00ZS
[0.05, 0.09, 0.93, 0.06]L
The settings page collapses to one column below 640 pixelsS
u-adaS
SESSION#s-103
TS#2026-09-21T02:24:00ZS
[0.04, 0.12, 0.90, 0.08]L
Use a minmax track so it reflows instead of snappingS
u-adaS
SESSION#s-201
TS#2026-09-18T00:00:00ZS
[0.07, 0.10, 0.06, 0.95]L
Summarise last quarter's support volume by product areaS
u-linusS
Awaiting request
Your next query starts here.

Choose an access pattern above, or build your own request. See what comes back and what it costs.

Write transactions, streams, tags and TTL are among the operations this browser build leaves out. dynoxide's native build has them.