1
Install
2
Start a database
Any PostgreSQL with pgvector works. For local development:
docker-compose.yml
3
Create the schema
Migrations are a deliberate step, not something that runs at startup. Twenty workers booting
at once and racing DDL is a real failure: Migration
CREATE TABLE IF NOT EXISTS is not race-safe in
PostgreSQL.0002 creates an unprivileged voicemem_app role. Give it a password and point
your agent at that, not at the admin role:4
Wire it into your agent
agent.py
Give the caller room to finish. LiveKit commits a turn after Nothing was injected into that first turn. āIām at a cafe right now.ā carries no signal to
retrieve on, so the agent answered a half-formed thought with an empty memory block. The
question that memory could have helped with landed in the next turn.The margin is narrow. Measured on real calls, a 461 ms pause stayed one turn and a 1.2 s
pause split, which is the 0.5 s threshold doing exactly what it says.You pay that delay on every turn, so treat 0.8 s as a starting point and tune it against
real calls. Retrieval itself is not the constraint here: it prefetches on interim
transcripts and finishes while the caller is still speaking.
min_delay of silence
(0.5 s by default) as soon as its turn detector rates what it has heard as a finished
sentence. A caller who pauses mid-thought is split into two turns, and the fragment is what
memory has to retrieve on:A pause past min_delay splits one thought into two turns
5
Confirm it remembers
Run the agent, say something about yourself, hang up, then reconnect and ask about it.Nothing was passed between the two sessions. The second one retrieved from Postgres.
First call
A later call, new session
What it costs
Measured, not estimated. 8 stored turns, 12 queries,text-embedding-3-small and gpt-4o-mini,
against a same-host pgvector/pgvector:pg17 container.
The single embedding call is almost all of it. Everything this package does costs about 19 ms.
That is why retrieval prefetches on interim transcripts: on a hit, the round trip already happened
while the caller was still speaking.
Writing runs in the background at 3.8 s p50 and 2 LLM calls per ingested turn, dropping to 1
when the store is empty and conflict resolution is skipped.

