Skip to main content

Memories

Learn how memories work in Trix - the fundamental unit for storing and retrieving context.

What are Memories?

Memories are the core data structure in Trix. Each memory represents a piece of information that your AI application should remember about users, conversations, or any other context. When you store a memory, Trix automatically:

  • Generates embeddings - Creates vector representations for semantic search
  • Extracts entities - Identifies people, places, products, and concepts
  • Extracts facts - Pulls out atomic, structured information
  • Builds relationships - Connects related memories in a knowledge graph
memory-structure.json
{
  "id": "mem_abc123def456",
  "content": "User prefers dark mode and minimal notifications",
  "space_id": "spc_xyz789",
  "tags": [
    "preferences",
    "ui"
  ],
  "metadata": {
    "category": "preferences",
    "confidence": 0.95,
    "source": "onboarding"
  },
  "priority": 1,
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T10:30:00Z"
}

Creating Memories

Use the memories.create() method to store new memories:

import { Trix } from '@trixdb/client';

const trix = new Trix({ apiKey: process.env.TRIX_API_KEY });

// Simple memory
const memory = await trix.memories.create({
  content: 'User prefers dark mode and compact layouts'
});

// Memory with options
const detailedMemory = await trix.memories.create({
  content: 'John mentioned he works at Acme Corp as a senior engineer',
  spaceId: 'user_123',  // Organize into a space
  tags: ['profile', 'work'],
  metadata: {
    source: 'conversation',
    confidence: 0.9,
    messageId: 'msg_456'
  },
  priority: 2  // Higher priority = more relevant in search
});

console.log(detailedMemory.id); // mem_abc123...

Memory Fields

FieldTypeDescription
contentstring (required)The text content of the memory. Max 10,000 characters.
spacestringSpace ID or name to organize the memory. Defaults to "default".
tagsstring[]Tags for filtering and categorization. Max 10 tags.
metadataobjectCustom key-value pairs. Supports nested objects and arrays.
prioritynumberImportance weight (0-10). Higher = more relevant in search. Default: 1.
ttlstringTime to live. Auto-deletes after duration (e.g., "24h", "7d", "30d").

Retrieving Memories

Semantic Search

Use memories.list() with a query to find memories by meaning, not just keywords:

// Semantic search finds related memories
const result = await trix.memories.list({
  q: 'What are the user interface settings?',
  spaceId: 'user_123',
  limit: 5
});

// Returns semantically similar memories
result.data.forEach(m => {
  console.log(`[${m.score.toFixed(2)}] ${m.content}`);
});

Trix uses vector embeddings for semantic search, so queries like "user settings" will match memories about "preferences" even without exact keyword matches.

Filtering

Combine semantic search with filters for precise results:

const result = await trix.memories.list({
  q: 'project requirements',
  spaceId: 'project_alpha',
  tags: ['requirements', 'specs'],
  metadata: {
    status: 'approved'
  },
  createdAfter: '2024-01-01',
  limit: 10
});

Get by ID

Retrieve a specific memory directly:

const memory = await trix.memories.get('mem_abc123def456');
console.log(memory.content);
console.log(memory.entities);
console.log(memory.facts);

Updating Memories

Modify existing memories with memories.update():

// Update content and metadata
const updated = await trix.memories.update('mem_abc123', {
  content: 'User prefers dark mode with high contrast',
  metadata: {
    lastUpdated: new Date().toISOString(),
    confidence: 0.98
  }
});

// Update only metadata (content unchanged)
await trix.memories.update('mem_abc123', {
  metadata: {
    verified: true
  }
});

// Add tags
await trix.memories.update('mem_abc123', {
  tags: ['verified', 'important']
});

When you update content, Trix automatically re-generates embeddings, re-extracts entities and facts, and updates relationships.

Deleting Memories

Remove memories you no longer need:

// Delete a single memory
await trix.memories.delete('mem_abc123');

// Delete multiple memories
await trix.memories.deleteMany({
  ids: ['mem_abc123', 'mem_def456', 'mem_ghi789']
});

// Delete by filter
await trix.memories.deleteMany({
  spaceId: 'temp_session',
  createdBefore: '2024-01-01'
});

// Delete all memories in a space
await trix.spaces.delete('user_123', { deleteMemories: true });

Deleting memories is permanent and cannot be undone. Consider using TTL for automatic expiration instead of manual deletion.

Memory Priority

Priority affects how memories rank in search results. Higher priority memories appear more prominently:

  • priority: 0 - Low importance, may be filtered out
  • priority: 1 - Default importance (most memories)
  • priority: 2-5 - Elevated importance
  • priority: 6-10 - Critical information, always surface

Reinforcing Memories

When a memory is useful, reinforce it to increase priority:

// Reinforce a helpful memory
await trix.memories.reinforce('mem_abc123');

// Priority increases by 0.1 each time, up to 10

Time to Live (TTL)

Set a TTL to automatically expire memories after a certain duration:

// Memory expires in 24 hours
await trix.memories.create({
  content: 'Session context that expires tomorrow',
  ttl: '24h'
});

// Memory expires in 7 days
await trix.memories.create({
  content: 'Weekly reminder context',
  ttl: '7d'
});

// Supported formats: 1h, 24h, 7d, 30d, 90d, 1y

TTL is useful for session-specific context, temporary preferences, or time-sensitive information that shouldn't persist indefinitely.

Audio & Voice Memories

Trix supports audio memories, allowing you to store voice recordings, meeting recordings, podcasts, and other audio content. Audio is automatically transcribed and indexed for semantic search.

Uploading Audio

import fs from 'fs';

// Upload audio file
const audioBuffer = fs.readFileSync('meeting.mp3');
const memory = await trix.memories.create({
  audio: audioBuffer,
  spaceId: 'meetings',
  metadata: {
    title: 'Q1 Planning Meeting',
    participants: ['Alice', 'Bob']
  }
});

console.log(memory.transcript);  // Auto-transcribed text

Supported Formats

MP3, WAV, M4A, WebM, OGG, and FLAC formats are supported, up to 100 MB per file. Audio longer than 2 hours is processed in chunks.

Transcription Options

const memory = await trix.memories.create({
  audio: audioBuffer,
  transcription: {
    language: 'en',
    diarization: true,
    timestamps: true,
    punctuation: true
  }
});

memory.transcript.segments.forEach(seg => {
  console.log(`[${seg.speaker}] ${seg.start}s: ${seg.text}`);
});

Searching Audio

Search audio memories just like text. Trix searches the transcript semantically:

const results = await trix.memories.list({
  q: 'quarterly budget discussion',
  type: 'audio',
  spaceId: 'meetings'
});

const segment = results.data[0].transcript.segments.find(s =>
  s.text.toLowerCase().includes('budget')
);
console.log(`Found at ${segment.start}s`);

Audio transcripts are semantically indexed, so searching for "financial plan" will match discussions about "budget allocation" even without exact keywords.

Image Memories

Trix supports image memories, allowing you to store photos, screenshots, documents, diagrams, and any visual content. Images are automatically analyzed using AI vision to extract text (OCR), generate descriptions, and enable visual similarity search.

Uploading Images

import fs from 'fs';

const imageBuffer = fs.readFileSync('receipt.jpg');
const memory = await trix.memories.create({
  image: imageBuffer,
  spaceId: 'receipts',
  metadata: {
    title: 'Office supplies receipt',
    vendor: 'Staples'
  }
});

console.log(memory.description);
console.log(memory.extracted_text);

Supported Formats

JPEG, PNG, WebP, GIF, HEIC, TIFF, BMP, and AVIF formats are supported, up to 20 MB per file. Images are automatically optimized and EXIF metadata is stripped for privacy.

AI Interpretation

When you upload an image, Trix automatically:

  • Extracts text (OCR) - Reads text from documents, signs, and screenshots
  • Generates descriptions - Creates detailed AI descriptions for search
  • Extracts facts - Identifies dates, amounts, names, and other structured data
  • Creates visual embeddings - Enables finding visually similar images
  • Generates thumbnails - Creates optimized previews for fast loading

Searching Images

Search images using natural language. Trix searches descriptions, extracted text, and visual content:

const results = await trix.memories.list({
  q: 'receipt for office supplies',
  type: 'image',
  spaceId: 'receipts'
});

const image = results.data[0];
console.log(image.description);
console.log(image.extracted_text);
console.log(image.thumbnail_url);

Visual Similarity Search

Find visually similar images using the visual embedding:

const similar = await trix.memories.findSimilar('mem_abc123', {
  type: 'image',
  limit: 5,
  threshold: 0.8
});

similar.forEach(m => {
  console.log(`[${m.similarity.toFixed(2)}] ${m.description}`);
});

const duplicates = await trix.memories.checkDuplicates({
  image: imageBuffer,
  threshold: 0.95
});

if (duplicates.length > 0) {
  console.log('Duplicate found:', duplicates[0].id);
}

Text-to-Image Search

Search for images using natural language descriptions:

const results = await trix.memories.searchVisual({
  query: 'sunset on the beach',
  limit: 10,
  threshold: 0.3
});

results.forEach(img => {
  console.log(`[${img.similarity.toFixed(2)}] ${img.filename}`);
});

Image Clustering

Automatically group visually similar images into clusters:

const clusters = await trix.memories.clusterImages({
  spaceId: 'photos',
  numClusters: 5
});

clusters.forEach(cluster => {
  console.log(`Cluster ${cluster.id}: ${cluster.images.length} images`);
});

Auto-Tagging

Generate automatic tags based on image content:

const tags = await trix.memories.autoTag('mem_abc123');
console.log(tags);

const results = await trix.memories.batchAutoTag([
  'mem_abc123',
  'mem_def456'
]);

Deduplication

Trix automatically prevents duplicate image uploads. When you upload an image that already exists, you'll receive a 409 Conflict response with the existing image ID:

try {
  const memory = await trix.memories.create({
    image: imageBuffer
  });
} catch (error) {
  if (error.status === 409) {
    console.log('Duplicate found:', error.existing_image_id);
  }
}

Visual similarity search uses specialized visual embeddings for high-quality visual matching. Text-to-image search uses the same embedding space, allowing natural language queries to find visually relevant images.

Memory Pinning

Memory pinning allows you to mark important memories so they never decay or get automatically archived. Pinned memories maintain their full relevance regardless of age.

Why Use Pinning?

  • Prevent decay - Pinned memories don't lose relevance over time
  • User preferences - Core settings that should always be remembered
  • Critical context - Essential facts that define user identity or needs
  • Compliance data - Information that must be retained for regulatory reasons

Pin on Creation

const memory = await trix.memories.create({
  content: 'User is allergic to peanuts - critical health information',
  is_pinned: true,
  tags: ['health', 'critical']
});

console.log(memory.is_pinned);
console.log(memory.pinned_at);

Pin an Existing Memory

await trix.memories.pin('mem_abc123');

const memory = await trix.memories.get('mem_abc123');
console.log(memory.is_pinned);

Unpin a Memory

await trix.memories.unpin('mem_abc123');

await trix.memories.update('mem_abc123', {
  is_pinned: false
});

List Pinned Memories

const pinnedMemories = await trix.memories.list({
  is_pinned: true,
  spaceId: 'user_123'
});

console.log(`Found ${pinnedMemories.data.length} pinned memories`);

const result = await trix.memories.list({
  q: 'preferences',
  is_pinned: true,
  limit: 10
});

Pinned memories are included in every relevant search with a slight boost to their relevance score. Use pinning sparingly to avoid cluttering results.

Memory Protection Levels

Protection levels control how memories can be deleted, providing safeguards for important or regulated data. There are three protection levels available.

LevelBehaviorUse Case
noneNormal deletion allowed. Memory is permanently removed.Default behavior for most memories
softRequires confirmation. Can be restored after deletion.Important memories that might need recovery
hardCannot be deleted through normal operations.Compliance, audit trails, legal requirements

Set Protection on Creation

const softProtected = await trix.memories.create({
  content: 'Important user agreement accepted on 2024-01-15',
  protection_level: 'soft',
  tags: ['legal', 'agreements']
});

const hardProtected = await trix.memories.create({
  content: 'GDPR consent recorded: user_123 consented to data processing',
  protection_level: 'hard',
  metadata: {
    consent_date: '2024-01-15',
    consent_version: '2.1',
    ip_address: '192.168.1.1'
  }
});

console.log(hardProtected.protection_level);

Update Protection Level

await trix.memories.update('mem_abc123', {
  protection_level: 'hard'
});

await trix.memories.update('mem_abc123', {
  protection_level: 'none'
}, { scope: 'admin' });

List Protected Memories

const protectedMemories = await trix.memories.list({
  protection_level: ['soft', 'hard']
});

const hardProtected = await trix.memories.list({
  protection_level: 'hard'
});

console.log(`Found ${hardProtected.data.length} compliance-protected memories`);

Memories with hard protection cannot be deleted through normal API calls. To delete hard-protected memories, you must use a special admin endpoint with audit logging enabled.

Soft Delete & Restore

Soft delete allows you to remove memories from active use while preserving the ability to restore them. Useful for "undo" functionality, recovering from accidental deletions, or maintaining audit trails.

Soft Delete vs Hard Delete

  • Soft delete - Memory is marked as deleted but data is preserved. Can be restored.
  • Hard delete - Memory is permanently removed. Cannot be recovered.

Soft Delete a Memory

await trix.memories.delete('mem_abc123', { soft: true });

const result = await trix.memories.list({ q: 'preferences' });

const deleted = await trix.memories.get('mem_abc123');
console.log(deleted.deleted_at);

Restore a Soft-Deleted Memory

await trix.memories.restore('mem_abc123');

const memory = await trix.memories.get('mem_abc123');
console.log(memory.deleted_at);
console.log(memory.restored_at);

List Deleted Memories

const deletedMemories = await trix.memories.list({
  include_deleted: 'only',
  spaceId: 'user_123'
});

console.log(`Found ${deletedMemories.data.length} deleted memories`);

const allMemories = await trix.memories.list({
  q: 'preferences',
  include_deleted: 'include'
});

Permanently Delete Soft-Deleted Memories

await trix.memories.delete('mem_abc123', { permanent: true });

await trix.memories.purgeDeleted({
  spaceId: 'user_123',
  olderThan: '30d'
});

await trix.memories.purgeDeleted({
  spaceId: 'user_123'
});

Soft-deleted memories are automatically purged after 90 days by default. You can configure this retention period in your space settings or at the account level.

Quality Scoring

Trix automatically scores each memory on a 0-1 scale based on its quality and usefulness. Quality scoring helps prioritize high-value information in search results.

Quality Factors

  • Information density - How much useful information is packed into the content
  • Clarity - How clear and unambiguous the content is
  • Relevance - How well the content relates to user/application context
  • Completeness - Whether the content provides full context or is fragmentary
  • Specificity - Specific facts score higher than vague statements
Score RangeQuality LevelDescription
0.8 - 1.0ExcellentClear, specific, complete information
0.6 - 0.8GoodUseful information with minor gaps
0.4 - 0.6FairUsable but could be improved
0.0 - 0.4PoorVague, incomplete, or low-value

Get Quality Score

const memory = await trix.memories.get('mem_abc123');

console.log({
  quality_score: memory.quality_score,
  quality_factors: memory.quality_factors
});

Filter by Quality Score

const highQuality = await trix.memories.list({
  q: 'user preferences',
  min_quality: 0.7,
  limit: 10
});

console.log(`Found ${highQuality.data.length} high-quality matches`);

const lowQuality = await trix.memories.list({
  max_quality: 0.4,
  spaceId: 'user_123'
});

Quality in Search Results

const result = await trix.memories.list({
  q: 'what does the user prefer?',
  limit: 5
});

result.data.forEach(m => {
  console.log(`[${m.score.toFixed(2)}] (quality: ${m.quality_score.toFixed(2)}) ${m.content}`);
});

const pureSemanticResult = await trix.memories.list({
  q: 'what does the user prefer?',
  include_quality_weight: false
});

Quality scoring happens automatically when memories are created or updated. Higher quality memories naturally surface more prominently in search results.

Best Practices

Do
  • Write clear, complete sentences
  • Include relevant context in content
  • Use meaningful tags for filtering
  • Set appropriate priority levels
  • Use spaces to organize by user/project
Avoid
  • Storing raw data without context
  • Creating duplicate memories
  • Using very long content (>5000 chars)
  • Storing sensitive data without encryption
  • Ignoring priority for important info

Content Guidelines

Memory content should be human-readable and contextually complete:

// Good: Clear, complete, contextual
await trix.memories.create({
  content: 'John mentioned he prefers Python for data science projects and has 5 years of experience',
  tags: ['skills', 'preferences']
});

// Bad: Fragmented, lacks context
await trix.memories.create({
  content: 'Python, 5 years'
});