Last updated

Memory Management Guide

This guide covers best practices for managing memories in your application using the Papr Memory API. We'll explore strategies for organizing, updating, and maintaining your memory store effectively.

Memory Structure

A memory in Papr consists of:

interface Memory {
  content: string;              // The main content
  type: "text" | "code_snippet" | "document";  // Content type
  metadata?: {
    topics?: string;           // Comma-separated topics
    hierarchical_structures?: string;  // Navigation path (e.g., "Business/Planning/Product")
    createdAt?: string;        // ISO timestamp
    location?: string;         // Optional location context
    "emoji tags"?: string;     // Emoji representations
    "emotion tags"?: string;   // Emotional context
    conversationId?: string;   // For linking related memories
    sourceUrl?: string;        // Original source if applicable
  };
  context?: Array<{
    role: "user" | "assistant";
    content: string;
  }>;
}

Organizing Memories

Using Metadata Effectively

  1. Topics
const memory = {
  content: "Discussion about new feature requirements",
  metadata: {
    topics: "product development, feature planning, user feedback",
    hierarchical_structures: "Product/Features/Requirements"
  }
};
  1. Emotional Context
const memory = {
  content: "Team celebration of successful launch",
  metadata: {
    "emoji tags": "🎉,🚀,🎯",
    "emotion tags": "excited, accomplished, proud"
  }
};
  1. Conversation Threading
const memory = {
  content: "Follow-up on feature discussion",
  metadata: {
    conversationId: "feat-123-discussion",
    sourceUrl: "https://meeting-notes.company.com/123"
  }
};

Memory Lifecycle Management

1. Creating Memories

Always validate and format your content before creation:

function prepareMemory(content: string, type: string) {
  return {
    content: content.trim(),
    type,
    metadata: {
      createdAt: new Date().toISOString(),
      topics: extractTopics(content),  // Your topic extraction logic
      hierarchical_structures: determineHierarchy(content)  // Your hierarchy logic
    }
  };
}

const memory = prepareMemory("Meeting notes...", "text");
const response = await fetch('https://memory.papr.ai/v1/memory', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': '<your-api-key>',
    'X-Client-Type': 'your_app_name',
    'Accept-Encoding': 'gzip'
  },
  body: JSON.stringify(memory)
});

2. Updating Memories

Keep track of memory changes:

const updateMemory = async (memoryId: string, updates: Partial<Memory>) => {
  const response = await fetch(`https://memory.papr.ai/v1/memory/${memoryId}`, {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': '<your-api-key>',
      'X-Client-Type': 'your_app_name',
      'Accept-Encoding': 'gzip'
    },
    body: JSON.stringify({
      ...updates,
      metadata: {
        ...updates.metadata,
        updatedAt: new Date().toISOString()
      }
    })
  });
  
  return response.json();
};

3. Batch Processing

Group related memories for efficient processing:

const batchAddMemories = async (memories: Memory[]) => {
  // Group memories by type
  const groupedMemories = memories.reduce((acc, memory) => {
    acc[memory.type] = acc[memory.type] || [];
    acc[memory.type].push(memory);
    return acc;
  }, {});

  // Process each group
  for (const [type, typeMemories] of Object.entries(groupedMemories)) {
    const response = await fetch('https://memory.papr.ai/v1/memory/batch', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': '<your-api-key>',
        'X-Client-Type': 'your_app_name',
        'Accept-Encoding': 'gzip'
      },
      body: JSON.stringify({
        memories: typeMemories,
        batch_size: 10
      })
    });

    const result = await response.json();
    handleBatchResults(result);  // Your result handling logic
  }
};

Search and Retrieval Strategies

Write detailed queries for better results:

const searchMemories = async (topic: string, context: string) => {
  const response = await fetch('https://memory.papr.ai/v1/memory/search', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': '<your-api-key>',
      'X-Client-Type': 'your_app_name',
      'Accept-Encoding': 'gzip'
    },
    body: JSON.stringify({
      query: `Find detailed discussions about ${topic} that include ${context}. Focus on items with specific examples or decisions made.`
    })
  });

  return response.json();
};

2. Result Processing

Handle search results effectively:

interface SearchResult {
  memories: Memory[];
  nodes: Node[];  // Graph nodes if available
}

function processSearchResults(results: SearchResult) {
  // Group by hierarchical structure
  const groupedResults = results.memories.reduce((acc, memory) => {
    const hierarchy = memory.metadata?.hierarchical_structures || 'Uncategorized';
    acc[hierarchy] = acc[hierarchy] || [];
    acc[hierarchy].push(memory);
    return acc;
  }, {});

  // Sort within each group by date
  for (const hierarchy in groupedResults) {
    groupedResults[hierarchy].sort((a, b) => {
      return new Date(b.metadata.createdAt) - new Date(a.metadata.createdAt);
    });
  }

  return groupedResults;
}

Error Handling and Monitoring

Implement robust error handling:

async function safeMemoryOperation<T>(operation: () => Promise<T>): Promise<T> {
  const maxRetries = 3;
  let lastError: Error;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await operation();
    } catch (error) {
      lastError = error;
      
      if (error.status === 429) {  // Rate limit
        const retryAfter = parseInt(error.headers.get('Retry-After') || '5');
        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
        continue;
      }
      
      if (error.status >= 500) {  // Server error
        await new Promise(resolve => setTimeout(resolve, attempt * 1000));
        continue;
      }
      
      throw error;  // Client error or other - don't retry
    }
  }

  throw lastError;
}

// Usage
const memory = await safeMemoryOperation(() => 
  fetch('https://memory.papr.ai/v1/memory/123')
    .then(res => res.json())
);

Best Practices Summary

  1. Content Organization

    • Use consistent hierarchical structures
    • Apply relevant emoji and emotion tags
    • Link related memories with conversationId
  2. Performance Optimization

    • Use batch operations for multiple memories
    • Enable gzip compression for searches
    • Monitor and handle rate limits
  3. Data Quality

    • Validate content before storage
    • Keep metadata consistent and updated
    • Use meaningful topics and hierarchies
  4. Error Handling

    • Implement retry logic for transient errors
    • Handle rate limits gracefully
    • Log and monitor error patterns
  5. Search Optimization

    • Write detailed, context-rich queries
    • Process and group results meaningfully
    • Cache frequently accessed memories

Next Steps