Memory
Core memory files the model edits with Anthropic's memory tool commands, archival facts found by similarity, and recall over a user's earlier messages.
The memory block keeps what an assistant should remember between chats.
It has three parts:
- Core memory: a few small files under
/memoriesthat go into every prompt. The model reads and edits them with the commands of Anthropic's memory tool (view,create,str_replace,insert,delete,rename). - Archival memory: a list of facts with embeddings, searched when the model asks.
- Recall: one embedding per chat message, so the assistant can find what a user said in an earlier chat. Temporary chats get none.
better-supabase sql add memory # adds tenant, access and vector-search as well| Table | Holds |
|---|---|
memories | Core files (kind core, with a path) and archival facts (archival), each with version |
ai_message_embeddings | One embedding per chat message and user |
Every memory belongs to a namespace: the user (the default), an agent,
a chat or a project of that user, or the organization. A project
namespace names an ai-chat project with projectId, so every chat in the
project can share it. A user reads only their
own memories and the organization's; nobody else reads them, admins
included. Changing organization memory needs the manage permission.
| Permission | Lets a member | Default roles |
|---|---|---|
ai.read | use memory in the tenant | owner, admin, member |
ai.admin | change the organization's memory | owner, admin |
Rename the keys with sql.modules.memory.permissions.read and .manage.
The maxContent option (100,000 characters by default) limits one memory,
and dimensions and type set the embedding column as in
knowledge.
Server
import { embedWith } from "better-supabase/ai-sdk/embeddings";
import { createMemory, rpcTransport } from "better-supabase/blocks/memory";
export const memoryFor = (supabase: SupabaseClient, admin: SupabaseClient) =>
createMemory({
transport: rpcTransport(supabase),
service: rpcTransport(admin),
embedder: embedWith("openai/text-embedding-3-small"),
});| Group | Methods |
|---|---|
core | view, write, strReplace, insert, remove, rename, list |
archival | save, search, list, forget |
recall | index, search |
| (top level) | run, render, saveExtracted, embedPending |
Each method takes the organization and an optional namespace, such as
{ scope: "agent", agentId } or { scope: "project", projectId }. The service role passes ownerId to act for
a user.
Core memory
const reply = await memory
.run(organizationId, {
command: "create",
path: "/memories/preferences.md",
file_text: "Prefers metric units.\n",
})
.orThrow();run takes one memory tool command and returns the text the model
expects back, such as File created successfully at: /memories/preferences.md.
Paths must stay under /memories. str_replace fails with
MEMORY_NO_MATCH or MEMORY_AMBIGUOUS unless the old text appears once,
and write with expectedVersion fails with MEMORY_CONFLICT when the
file changed. render(organizationId) returns the core files as delimited
text for the system prompt, cut at maxRender characters (8,000).
Archival memory and recall
await memory.archival
.save(organizationId, "Works in the Lisbon office")
.orThrow();
const hits = await memory.archival
.search(organizationId, "where do they work")
.orThrow();Search ranks by embedding similarity and full text together.
saveExtracted(organizationId, facts) saves only facts that aren't close
to one already saved (similarity 0.92 by default, dedupeThreshold);
forget(id, { supersededBy }) keeps the old fact but hides it.
saveExtracted embeds every fact in one embedder call.
recall.index(message) runs as the service role after a message is
stored; recall.search(organizationId, query, { excludeChat }) returns the
caller's closest earlier messages. Facts saved without an embedder wait
for embedPending(), which embeds a batch in one call and writes it with
one set_memory_embeddings RPC. Each vector is written only while the
fact still has the text it was computed from, so a fact edited meanwhile
stays pending. A wrong number of vectors, mixed lengths or non-finite
numbers fail with the hint EMBEDDING_INVALID. Search sets
hnsw.iterative_scan for its query and puts the caller's value back.
Documents for agent runtimes
memory.documents stores versioned text documents under an opaque scope
key and a path, for runtimes that keep their own memory format, such as
eve's file memory. Only the service role reads and writes them.
const doc = await memory.documents.read("eve", "user:42/notes.md").orThrow();
await memory.documents
.write("eve", "user:42/notes.md", "- Prefers short answers", {
expectedVersion: doc?.version ?? null,
})
.orThrow();A write names the version it read (null when the document must not
exist yet); a stale version fails with the hint MEMORY_DOCUMENT_CONFLICT,
so the caller reads again and retries. expiresIn sets a lifetime in
seconds, and documents.purge() deletes expired documents.
eve uses the table for file memory and for its recall
records.
AI SDK
better-supabase/ai-sdk/memory gives the model the
memory tool, a recall tool, core memory in its instructions and a job that
extracts facts from a conversation.
Last updated on
Knowledge
Documents chunked and embedded per organization, agent, project, chat or user, with hybrid search that ranks full text and vector matches together.
Agents
Saved assistants with their own instructions, model, tools, connectors and knowledge, shared in an organization or a public store with installs and ratings.