memory.add
Saves a new memory with automatic embedding generation for semantic search.
Parameters
User identifier for memory isolation. Must be a stable, unique ID for each user.
The text content to save. Should be a complete, self-contained statement.content: 'User prefers TypeScript over JavaScript for type safety'
Write memories as complete sentences that make sense out of context.
Optional metadata for categorization and filtering.metadata: {
category: 'preference',
tags: ['programming', 'languages'],
importance: 'high',
customField: 'value'
}
Response
Unique identifier (UUID) for the memory
Tenant identifier (API key owner)
ISO 8601 timestamp of creation
ISO 8601 timestamp of last update
Examples
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from '@satori/server';
const client = createTRPCClient<AppRouter>({
links: [
httpBatchLink({
url: 'https://api.satori.dev/trpc',
headers: {
'x-api-key': process.env.SATORI_API_KEY!,
},
}),
],
});
const memory = await client.memory.add.mutate({
userId: 'user-123',
content: 'User prefers dark mode in all applications',
metadata: {
category: 'preference',
tags: ['ui', 'theme'],
},
});
console.log('Memory saved:', memory.id);
{
"userId": "user-123",
"content": "User prefers TypeScript over JavaScript for type safety",
"metadata": {
"category": "preference",
"tags": ["programming", "languages"],
"importance": "high"
}
}
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"content": "User prefers TypeScript over JavaScript for type safety",
"userId": "user-123",
"clerkUserId": "user_372Icb...",
"metadata": {
"category": "preference",
"tags": ["programming", "languages"],
"importance": "high"
},
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
Embedding Generation
When you save a memory, Satori automatically:
- Sends the content to OpenAI’s
text-embedding-3-small model
- Receives a 1536-dimensional vector
- Stores both the text and embedding in PostgreSQL
This enables semantic search without any additional work on your part.
Embedding generation typically takes 50-100ms. The API call returns after the memory is fully saved with its embedding.
Best Practices
Write complete, self-contained memories
// ✅ Good: Complete sentence with context
await client.memory.add.mutate({
userId: 'user-123',
content: 'User prefers TypeScript over JavaScript for type safety',
});
// ❌ Bad: Too vague
await client.memory.add.mutate({
userId: 'user-123',
content: 'likes TS',
});
Use metadata for organization
// Search first to avoid duplicates
const existing = await client.memory.search.query({
userId: 'user-123',
query: 'TypeScript preference',
threshold: 0.9,
});
if (existing.length === 0) {
await client.memory.add.mutate({
userId: 'user-123',
content: 'User prefers TypeScript',
});
}
Error Handling
try {
const memory = await client.memory.add.mutate({
userId: 'user-123',
content: 'Important information',
});
console.log('Memory saved:', memory.id);
} catch (error) {
if (error.message.includes('Unauthorized')) {
console.error('Invalid API key');
} else if (error.message.includes('rate limit')) {
console.error('Rate limit exceeded, retry later');
} else {
console.error('Failed to save memory:', error);
}
}