Verified by the sovseal team

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 zod

API 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();
}

On this page