Packages
@anvia/memory-drizzle: Usage Patterns
Common ways to use Drizzle-backed Anvia memory.
Exported table definitions
Use drizzleMemorySchema when you want all memory tables:
export const schema = {
...drizzleMemorySchema,
};
Use individual table exports when your schema file groups tables manually:
export { agentMemorySessions, agentMemoryMessages, agentMemoryErrors };
Tenant-scoped conversations
const memory = createDrizzleMemoryStore(db, {
scope: { metadataKeys: ["tenantId"] },
});
The default scope includes sessionId and userId; metadata keys add product tenancy or workspace isolation. The adapter reads selected keys from context.metadata, so the matching session call must pass the same values:
const session = agent.session(conversation.id, {
userId: user.id,
metadata: { tenantId: user.tenantId },
});
Set includeUserId: false only for intentionally shared tenant memory. Scope chooses which database rows to read and write; your app still owns authorization.
Load initial messages
Use session.messages() on the server when a React page needs to render an existing thread:
export async function GET(request: Request, params: { threadId: string }) {
const user = await requireUser(request);
const agent = createSupportAgent(user);
const messages = await agent
.session(params.threadId, {
userId: user.id,
metadata: { tenantId: user.tenantId },
})
.messages();
return Response.json({ messages });
}
The response contains core Anvia Message[]. Convert those messages before passing them to useChat:
import type { Message } from "@anvia/core";
import { initialMessagesFromMemory, useChat } from "@anvia/react";
export function SupportChat({
threadId,
messages,
}: {
threadId: string;
messages: Message[];
}) {
const chat = useChat({
endpoint: `/api/threads/${threadId}/chat`,
initialMessages: initialMessagesFromMemory(messages),
});
return <ChatProvider controller={chat}>{/* thread */}</ChatProvider>;
}
initialMessages hydrates browser state only. The stream route should still call agent.session(...).prompt(latestUserMessage) so Drizzle memory loads authoritative history on the server.
Advisory locking
Append and failed-run writes use Postgres advisory locks by default through db.execute(...). Set lock: "none" only when your deployment serializes same-scope writes another way.
