Vercel AI SDK Memory Integration
Build stateful, personalized conversational applications with Vercel AI SDK and the local-first sovseal memory layer.
Integrate Vercel AI SDK with sovseal to provide your chat interfaces and agents with persistent, user-scoped memory. By combining Vercel AI SDK's tool calling mechanisms with @sovseal/sdk client snapshots, you can maintain context across sessions with zero-knowledge cryptographic integrity.
By default, the AgentStateClient runs client-side encryption (AES-256-GCM) so the remote replication endpoint only ever stores ciphertext, keeping user conversation history private.
Installation
Install the @sovseal/sdk client along with the Vercel AI SDK packages:
npm install ai @ai-sdk/openai @sovseal/sdk zodAPI Route Implementation
Here is a complete, streaming-safe implementation of a Next.js App Router API route (app/api/chat/route.ts). It initializes the AgentStateClient, restores the user's latest persistent context, injects it into the system message, and saves new context after the completion:
import { NextRequest } from "next/server";
import { streamText, tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { AgentStateClient } from "@sovseal/sdk";
import { z } from "zod";
// Initialize the AgentStateClient config
const client = new AgentStateClient({
endpoint: "https://ksrlmubaxzwufziwarps.supabase.co/functions/v1/v2-agent-state",
apiKey: process.env.SOVSEAL_API_KEY || "", // paid API key or local free token
});
// Import key for AES decryption (treat like a user passkey)
const getCryptoKey = async () => {
const rawKey = Buffer.from(process.env.SOVSEAL_ENCRYPTION_KEY || "", "base64");
return crypto.subtle.importKey(
"raw",
rawKey,
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
};
export async function POST(req: NextRequest) {
const { messages, userId } = await req.json();
const encryptionKey = await getCryptoKey();
// 1. Restore the user's persistent memory context
let persistentContext = "";
try {
const { receipt } = await client.restore({ agentId: userId });
persistentContext = receipt.active_context?.content || "";
} catch (err) {
console.warn("No prior memory state found, starting fresh.", err);
}
// 2. Setup the tool definitions for the agent
const response = streamText({
model: openai("gpt-4o"),
messages,
system: `You are a helpful assistant. Here is the context from previous conversations:
${persistentContext}`,
tools: {
storeMemory: tool({
description: "Store a new fact or preference about the user for future conversations.",
parameters: z.object({
fact: z.string().describe("A declarative fact about the user (e.g., 'User prefers dark mode')"),
}),
execute: async ({ fact }) => {
// Asynchronously snapshot the new state to local-first replication
await client.snapshot({
key: encryptionKey,
payload: {
agent_id: userId,
sequence_number: Date.now(),
parent_snapshot: null,
policy_hash: "0".repeat(64),
active_context: { content: persistentContext + "\n" + fact },
timestamp: new Date().toISOString(),
},
});
return { success: true, stored: fact };
},
}),
},
});
return response.toDataStreamResponse();
}