Quick Start
Give your Vercel AI SDK agent long-term memory in under 5 minutes.
Overview
Souvenir provides automatic memory tools for AI agents. Your agent will:
- Automatically store important information
- Retrieve relevant memories when needed
- Build a knowledge graph of entities and relationships
- Remember across conversations
You just create the tools and add them to your agent. That's it.
Setup
1. Create Souvenir Instance (Per User/Session)
import { Souvenir, AIEmbeddingProvider } from '@upstart.gg/souvenir';
import { openai } from '@ai-sdk/openai';
// Create one instance per user/session
const souvenir = new Souvenir(
{
databaseUrl: process.env.DATABASE_URL!,
embeddingDimensions: 1536,
},
{
sessionId: 'user-123', // Bind to specific user/session
embeddingProvider: new AIEmbeddingProvider(
openai.embedding('text-embedding-3-small')
),
processorModel: openai('gpt-4o-mini'),
}
);Important: Create a separate Souvenir instance for each user/session. Each instance is bound to a specific sessionId, ensuring complete data isolation.
Session ID Format: The sessionId can be any string (max 255 characters) - use whatever format works for your application:
- User IDs:
'user-123','alice@example.com','auth0|507f1f77bcf86cd799439011' - Session IDs:
'session-abc123','conv-2024-01-15-xyz' - Custom formats:
'workspace:acme:user:bob','tenant-42-user-99'
2. Create Memory Tools
import { createSouvenirTools } from '@upstart.gg/souvenir/tools';
const tools = createSouvenirTools(souvenir);That's it! You now have 3 tools:
storeMemory- Store important informationsearchMemory- Search past memories (with configurable retrieval strategies)deleteMemory- Delete specific memories by node ID
3. Use in Your Agent
import { generateText } from 'ai';
const result = await generateText({
model: openai('gpt-4'),
tools,
maxSteps: 10,
messages: [
{
role: 'user',
content: 'My name is Alice and I work as a software engineer at Acme Corp.',
},
],
});
console.log(result.text);
// Agent automatically stores: "User's name is Alice, works as software engineer at Acme Corp"Complete Example
Here's a full working agent with memory:
import { Souvenir, AIEmbeddingProvider } from '@upstart.gg/souvenir';
import { createSouvenirTools } from '@upstart.gg/souvenir/tools';
import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';
// Helper to create Souvenir instance for a user
function createUserMemory(sessionId: string) {
return new Souvenir(
{
databaseUrl: process.env.DATABASE_URL!,
embeddingDimensions: 1536,
},
{
sessionId, // Bind to user session
embeddingProvider: new AIEmbeddingProvider(
openai.embedding('text-embedding-3-small')
),
processorModel: openai('gpt-4o-mini'),
}
);
}
// Create memory instance for user
const bobMemory = createUserMemory('user-bob');
const bobTools = createSouvenirTools(bobMemory);
// Chat with agent
async function chat(message: string, tools: any) {
const result = await generateText({
model: openai('gpt-4'),
tools,
maxSteps: 10,
messages: [
{
role: 'system',
content: 'You are a helpful assistant with long-term memory. Store important information about the user and recall it when relevant.',
},
{
role: 'user',
content: message,
},
],
});
return result.text;
}
// First conversation
const response1 = await chat(
"Hi! I'm Bob. I love Italian food and I'm allergic to shellfish.",
bobTools
);
console.log(response1);
// Agent stores: name=Bob, loves Italian food, allergic to shellfish
// Later conversation (same session)
const response2 = await chat(
"Can you recommend a restaurant?",
bobTools
);
console.log(response2);
// Agent searches memory, finds preferences, recommends Italian restaurant without shellfish
await bobMemory.close();Multi-User Pattern:
// Each user gets their own isolated memory
const aliceMemory = createUserMemory('user-alice');
const bobMemory = createUserMemory('user-bob');
const aliceTools = createSouvenirTools(aliceMemory);
const bobTools = createSouvenirTools(bobMemory);
// Complete data isolation - Alice and Bob can't access each other's memoriesHow It Works
Behind the Scenes
When your agent runs:
- Agent receives user message
- Agent decides whether to:
- Store new information → calls
storeMemorytool - Retrieve past information → calls
searchMemorytool (with optional strategy parameter) - Remove outdated information → calls
deleteMemorytool
- Store new information → calls
- Souvenir processes the information:
- Chunks text
- Extracts entities and relationships
- Builds knowledge graph
- Generates embeddings
- Agent uses the retrieved information to respond
Knowledge Graph
Based on research (arXiv:2505.24478), Souvenir builds a knowledge graph:
User Message: "I'm Alice and I work at Acme Corp"
Extracts:
- Entity: Alice (person)
- Entity: Acme Corp (organization)
- Relationship: Alice → works_at → Acme Corp
Stores in graph for future retrievalRetrieval Strategies
The agent can use different retrieval strategies:
- Vector search - Find similar memories
- Graph traversal - Find connected information
- Hybrid - Combine both approaches
The tools automatically choose the best strategy based on the query.
Multi-User Support
Use sessionId to separate user memories:
// User 1
await chat("I love pizza", 'user-alice');
// User 2
await chat("I love sushi", 'user-bob');
// Each user has separate memoriesWhat Gets Stored?
The agent automatically stores:
- User preferences ("I like dark mode")
- Facts about the user ("My birthday is June 5")
- Important context ("I'm working on Project X")
- Decisions and agreements ("Let's meet next Tuesday")
- Relationships ("Alice works with Bob")
The agent does NOT store:
- Trivial information ("Hello", "Thanks")
- Questions without answers
- Temporary context
Configuration
Minimal Configuration
import { Souvenir, AIEmbeddingProvider } from '@upstart.gg/souvenir';
import { openai } from '@ai-sdk/openai';
const souvenir = new Souvenir(
{
databaseUrl: process.env.DATABASE_URL!,
embeddingDimensions: 1536, // Must match your embedding model
},
{
sessionId: 'user-123',
embeddingProvider: new AIEmbeddingProvider(
openai.embedding('text-embedding-3-small')
),
}
);With Full Options
import { Souvenir, AIEmbeddingProvider } from '@upstart.gg/souvenir';
import { openai } from '@ai-sdk/openai';
const souvenir = new Souvenir(
{
databaseUrl: process.env.DATABASE_URL!,
embeddingDimensions: 1536,
// Optional: Adjust chunking (defaults are good for most cases)
chunkSize: 1000,
chunkOverlap: 200,
chunkingMode: 'recursive', // or 'token'
// Optional: Filter search results
minRelevanceScore: 0.7,
maxResults: 10,
},
{
// Required: Session identifier for data isolation
sessionId: 'user-123',
// Required: Embedding provider
embeddingProvider: new AIEmbeddingProvider(
openai.embedding('text-embedding-3-small')
),
// Required: LLM for entity/relationship extraction
processorModel: openai('gpt-4o-mini'),
// Optional: Customize extraction prompts
promptTemplates: {
entityExtraction: 'Extract entities...',
relationshipExtraction: 'Extract relationships...',
},
}
);Production Tips
1. Use Session IDs
Always pass sessionId to separate user memories:
await generateText({
model: openai('gpt-4'),
tools,
sessionId: userId, // Important!
messages: [...],
});2. System Prompt
Guide the agent on when to use memory:
const systemPrompt = `You are a helpful assistant with long-term memory.
IMPORTANT:
- Store important user information (preferences, facts, goals)
- Retrieve memories when relevant to the conversation
- Don't store trivial information like greetings`;3. Max Steps
Allow enough steps for tool usage:
await generateText({
model: openai('gpt-4'),
tools,
maxSteps: 10, // Allow multiple tool calls
messages: [...],
});4. Error Handling
try {
const result = await generateText({
model: openai('gpt-4'),
tools,
messages: [...],
});
return result.text;
} catch (error) {
console.error('Agent error:', error);
// Fallback behavior
}Next Steps
- ETL Pipeline - How data flows through the system
- Retrieval Strategies - Different ways to search
- Chunking - Text chunking options
Troubleshooting
Agent doesn't use memory tools
- Check
maxStepsis high enough (minimum 5) - Add guidance in system prompt
- Verify
sessionIdis passed
Memories aren't retrieved
- Check embedding dimensions match your model
- Lower
minRelevanceScoreif too strict - Verify database migrations ran correctly
Performance is slow
- Entity/relationship extraction is async (runs in background)
- Retrieval is fast (uses vector index)
- Consider using
gpt-4o-minifor processing