diff --git a/docs/cookbooks/companions/nodejs-companion.mdx b/docs/cookbooks/companions/nodejs-companion.mdx index 5b408d17a..7e9accb58 100644 --- a/docs/cookbooks/companions/nodejs-companion.mdx +++ b/docs/cookbooks/companions/nodejs-companion.mdx @@ -130,8 +130,8 @@ As users interact with the system, Mem0's memory system continuously learns and --- - - Separate user and agent memories to keep your companion's personality consistent. + + Separate user, agent, and session context to keep your companion consistent. Run the full showcase app to see memory-powered companions in action. diff --git a/docs/cookbooks/essentials/building-ai-companion.mdx b/docs/cookbooks/essentials/building-ai-companion.mdx index 48f7c1347..6cbaf0e12 100644 --- a/docs/cookbooks/essentials/building-ai-companion.mdx +++ b/docs/cookbooks/essentials/building-ai-companion.mdx @@ -516,8 +516,8 @@ Before launching: --- - - Separate user and agent memories so companions stay consistent across sessions. + + Keep companions from leaking context by combining user, agent, and session scopes. Organize customer context to keep assistants responsive at scale. diff --git a/docs/cookbooks/essentials/building-ai-with-personality.mdx b/docs/cookbooks/essentials/building-ai-with-personality.mdx deleted file mode 100644 index 0c740d871..000000000 --- a/docs/cookbooks/essentials/building-ai-with-personality.mdx +++ /dev/null @@ -1,603 +0,0 @@ ---- -title: Scope User vs Agent Memories -description: "Use **user_id** and **agent_id** to balance personalization with consistent assistant behavior." ---- - -# Build AI with Distinct Personalities - -While building memory systems for AI apps, you need to juggle between agent and user memories. The user delivers information from their side, but there's often value inside the agent's responses as well. - -Unlike other memory APIs, we built one that allows you the flexibility to store memory from all sources. User and agent memories in Mem0 are handled by: - -- **user_id** - Memories about specific users -- **agent_id** - Memories from the agent itself - -In this guide, you'll see how these parameters work together, along with practical examples to help you build a fitness coach that remembers user workouts while maintaining a consistent coaching personality. - ---- - -## User Memories - -Let's start by tracking individual user workouts. We'll use **`user_id`** to keep each person's data separate. - -```python -from openai import OpenAI -from mem0 import MemoryClient -import os - -openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) -mem0_client = MemoryClient() - -# Sarah logs her workout -mem0_client.add( - "Completed 5K run in 28 minutes - felt great!", - user_id="sarah" -) - -# Mike logs his workout -mem0_client.add( - "Bench press: 185 lbs x 10 reps, 3 sets", - user_id="mike" -) - -``` - -Now when we coach Sarah, we retrieve only her workout history: - -```python -# Get Sarah's workout history -sarah_history = mem0_client.search( - "What exercises has Sarah done recently?", - filters={"user_id": "sarah"} -) - -# Generate coaching advice -response = openai_client.chat.completions.create( - model="gpt-4", - messages=[ - {"role": "system", "content": "You're a supportive fitness coach."}, - {"role": "user", "content": f"Based on this history: {sarah_history}, suggest the next workout."} - ] -) - -print(response.choices[0].message.content) - -``` - -**Output:** - -``` -Great job on that 5K! Your endurance is building nicely. Let's add some -strength work to complement your running. Try 3 sets of bodyweight squats -(15 reps each) to strengthen your legs and improve your running power. - -``` - - -**Expected output:** Sarah gets running advice based on her 5K, not Mike's bench press data. The **`user_id`** filter ensures memories are isolated—each user only sees their own workout history. - - -This works perfectly! Each user has private workout history, and Sarah never sees Mike's data. - ---- - -## Adding Coach Personality - -Our fitness coach needs a consistent personality - supportive, motivational, and celebrates small wins. Let's see what happens if we try storing this with **`user_id`**: - -```python -# Adding coach personality for Sarah -mem0_client.add( - "I'm a supportive fitness coach who celebrates every achievement and uses athlete-focused language", - user_id="sarah" -) - -# Adding the same personality for Mike -mem0_client.add( - "I'm a supportive fitness coach who celebrates every achievement and uses athlete-focused language", - user_id="mike" -) - -# For 1,000 users, we'd repeat this 1,000 times... - -``` - -This approach has some limitations: - -1. **Duplication**: We're storing the same coaching personality 1,000 times for 1,000 users -2. **Hard to update**: Want to change the coaching style? Update 1,000 memories -3. **Mixed with user data**: Coach personality and user workouts are stored together, making queries complex - - -Storing agent personality with **`user_id`** doesn't scale. For 10,000 users, you'd duplicate the same personality 10,000 times. Updating the coaching style means updating 10,000 separate memories. This wastes storage and makes maintenance impossible. - - -What if the coach could have a personality that's shared across all users? - ---- - -## Agent Memories - -Here's where **`agent_id`** comes in. We can store the coach's personality once and share it across all users: - -```python -# Store coach personality ONCE with agent_id -mem0_client.add( - "I'm FitCoach - a supportive fitness coach who celebrates every achievement. " - "I use motivational language, focus on progress over perfection, and help users build sustainable habits.", - agent_id="fitcoach_v1" -) - -# Sarah's workout (still private) -mem0_client.add( - "Completed 5K run in 28 minutes", - user_id="sarah" -) - -# Mike's workout (still private) -mem0_client.add( - "Bench press: 185 lbs x 10 reps, 3 sets", - user_id="mike" -) - -``` - -Now when coaching Sarah, we retrieve both the agent's personality AND her workout history: - -```python -# Get both coach personality and Sarah's workouts -coaching_context = mem0_client.search( - "coaching context for Sarah", - filters={ - "OR": [ - {"agent_id": "fitcoach_v1"}, # Coach personality - {"user_id": "sarah"} # Sarah's workout history - ] - } -) - -# Generate personalized coaching -response = openai_client.chat.completions.create( - model="gpt-4", - messages=[ - {"role": "system", "content": str(coaching_context)}, - {"role": "user", "content": "What should I focus on in my next workout?"} - ] -) - -print(response.choices[0].message.content) - -``` - -**Output:** - -``` -Amazing work on that 5K! 🎉 You're crushing your running goals! - -Now let's build some complementary strength. I recommend adding bodyweight -squats to your routine - they'll make you an even stronger runner. Start -with 3 sets of 15 reps, and remember: progress over perfection! - -``` - -Notice how the response has the motivational tone (from **`agent_id`**) combined with personalized advice based on Sarah's 5K run (from **`user_id`**). - -The coach personality is now: - -- ✅ Stored once, shared by all users -- ✅ Easy to update (change one memory, affects all users) -- ✅ Cleanly separated from user workout data - - -**Expected behavior:** The response combines the motivational tone (from **`agent_id`**) with Sarah's specific 5K progress (from **`user_id`**). One agent personality, infinite users—update the agent once, and all users get the new coaching style. - - ---- - -## Combining Both: Relationship Memories - -There's a third type of memory - one that captures the relationship between a specific user and the coach. To store these, use `metadata` to track which agent the relationship is with: - -```python -# Coach personality (shared across all users) -mem0_client.add( - "I'm FitCoach - supportive and motivational", - agent_id="fitcoach_v1" -) - -# Sarah's workout data (private to Sarah) -mem0_client.add( - "Goal: Run a half marathon by June. Currently runs 5K comfortably.", - user_id="sarah" -) - -# Sarah-Coach relationship (stored as user memory with agent context in metadata) -mem0_client.add( - "Sarah and I have an inside joke: 'No pain, no protein shake!' " - "She responds best to gentle encouragement after tough workouts.", - user_id="sarah", - metadata={"agent_id": "fitcoach_v1", "type": "relationship"} -) - -# Mike-Coach relationship (different from Sarah's) -mem0_client.add( - "Mike prefers data-driven feedback with specific numbers and percentages. " - "Less motivational talk, more concrete metrics.", - user_id="mike", - metadata={"agent_id": "fitcoach_v1", "type": "relationship"} -) - -``` - -Now when coaching Sarah, retrieve her data including relationship with this specific coach: - -```python -# Get Sarah's memories including relationship with fitcoach_v1 -sarah_context = mem0_client.search( - "How should I coach Sarah today?", - user_id="sarah", - filters={"metadata": {"agent_id": "fitcoach_v1"}} -) - -# Get coach personality -coach_personality = mem0_client.search( - "coaching personality", - agent_id="fitcoach_v1" -) - -# Combine both contexts -full_context = str(coach_personality) + "\\n" + str(sarah_context) - -response = openai_client.chat.completions.create( - model="gpt-4", - messages=[ - {"role": "system", "content": full_context}, - {"role": "user", "content": "Just finished today's workout!"} - ] -) - -print(response.choices[0].message.content) - -``` - -**Output:** - -``` -Awesome work today! 💪 No pain, no protein shake, right? 😄 - -You're making real progress toward that half marathon goal. Keep this -momentum going - your consistency is your superpower! - -``` - -When coaching Mike with the same approach: - -```python -# Get Mike's memories including relationship with fitcoach_v1 -mike_context = mem0_client.search( - "How should I coach Mike today?", - user_id="mike", - filters={"metadata": {"agent_id": "fitcoach_v1"}} -) - -coach_personality = mem0_client.search( - "coaching personality", - agent_id="fitcoach_v1" -) - -full_context = str(coach_personality) + "\\n" + str(mike_context) - -# ... same coaching code ... - -``` - -**Output:** - -``` -Solid session. Your bench press shows 8% improvement over last week -(171 lbs avg to 185 lbs). Target: 200 lbs by end of month. -On track at current rate (+3.2% weekly). - -``` - -Same coach, completely different experience based on each user's relationship preferences stored in metadata. - - -**Relationship memories** are stored with **`user_id`** (they're private to each user) but include `agent_id` in metadata to track which agent the relationship is with. This lets you retrieve the user's preferences for how this specific agent should interact with them. - - ---- - -## Putting It All Together - -Here's a complete example showing all three memory layers working together: - -```python -from openai import OpenAI -from mem0 import MemoryClient -import os - -# Initialize clients -openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) -mem0_client = MemoryClient() - -# Layer 1: Agent personality (shared) -mem0_client.add( - "I'm FitCoach - supportive, motivational, celebrates small wins", - agent_id="fitcoach_v1", - metadata={"type": "personality"} -) - -# Layer 2: User profile (private) -mem0_client.add( - "Sarah's goal: Run half marathon by June. Currently comfortable at 5K distance.", - user_id="sarah", - metadata={"type": "profile"} -) - -# Layer 3: Relationship (stored as user memory with agent context in metadata) -mem0_client.add( - "Sarah responds best to encouragement. Inside joke: 'No pain, no protein shake!'", - user_id="sarah", - metadata={"agent_id": "fitcoach_v1", "type": "relationship"} -) - -# Log today's workout -mem0_client.add( - "Completed 8K run in 45 minutes - new personal record!", - user_id="sarah", - metadata={"type": "workout", "date": "2025-01-23"} -) - -# Generate coaching response -# Get Sarah's context (includes all her memories) -sarah_context = mem0_client.search( - "Generate coaching advice for Sarah", - user_id="sarah" -) - -# Get coach personality -coach_personality = mem0_client.search( - "coaching personality", - agent_id="fitcoach_v1" -) - -# Combine contexts -full_context = str(coach_personality) + "\\n" + str(sarah_context) - -response = openai_client.chat.completions.create( - model="gpt-4", - messages=[ - {"role": "system", "content": full_context}, - {"role": "user", "content": "Just finished my run today!"} - ] -) - -print(response.choices[0].message.content) - -``` - -**Output:** - -``` -🎉 YES! 8K is a HUGE milestone! You just crushed your previous distance! - -Remember when you could barely do 5K? Look at you now! That half marathon -in June is looking more achievable every single day. No pain, no protein -shake - and today, you EARNED that shake! 💪 - -Next week, let's aim for 9K. You're ready for it! - -``` - -The response combines: - -- ✅ Motivational tone (agent personality) -- ✅ Specific goal reference (Sarah's profile) -- ✅ Inside joke (relationship memory) -- ✅ Progress tracking (workout history) - ---- - -![image.png](building_ai_with_personality 295f22c70c908182affdfc87ec79f2db/image.png) - -**Three memory layers:** - -1. **Agent memories** (blue) - Shared personality and capabilities -2. **User memories** (red) - Private workout data and goals -3. **Relationship memories** (purple) - User memories with agent context stored in metadata - ---- - -## When to Use What - -### Use **`user_id`** only (most apps) - -**Best for:** Apps that just need to track user-specific data without AI personality - -**Examples:** - -- Todo lists -- Note-taking apps -- Personal finance trackers -- Support ticket history - -```python -mem0_client.add( - "Bought groceries for $127.43", - user_id="sarah" -) - -``` - ---- - -### Use **`agent_id`** only (rare) - -**Best for:** AI tools that work the same for everyone, no user-specific data - -**Examples:** - -- Calculator bots -- Language translators -- Company policy assistants (same policies for all) - -```python -mem0_client.add( - "I can calculate: arithmetic, algebra, basic calculus. I cannot solve differential equations.", - agent_id="calculator_v1" -) - -``` - ---- - -### Use both **`user_id`** and **`agent_id`** (AI with personality) - -**Best for:** AI agents with persistent personalities that remember individual users - -**Examples:** - -- Fitness coaches (this guide!) -- Educational tutors -- AI companions -- Therapy/mental health bots -- Game NPCs with character development - -```python -# Agent personality (shared across all users) -mem0_client.add( - "Coaching personality and style", - agent_id="agent_name" -) - -# User data (private) -mem0_client.add( - "User's goals and progress", - user_id="user_name" -) - -# Relationship (user memory with agent context in metadata) -mem0_client.add( - "User's relationship with this specific agent", - user_id="user_name", - metadata={"agent_id": "agent_name", "type": "relationship"} -) - -``` - ---- - - -**When to combine user_id + agent_id:** Use both when your AI has a consistent personality that should work the same for everyone (agent_id), while also tracking individual user data (user_id). Most personal AI assistants, coaches, and tutors fit this pattern. - - ---- - -## Best Practices - -### 1. Use clear naming conventions - -```python -# Good: Descriptive and versioned -agent_id="fitcoach_v1" -user_id="sarah_123" - -# Bad: Generic and unclear -agent_id="agent1" -user_id="user_abc" - -``` - -### 2. Tag memories with metadata - -```python -# For relationship memories, store agent context in metadata -mem0_client.add( - content, - user_id="sarah", - metadata={ - "agent_id": "fitcoach_v1", - "type": "relationship", - "version": "v1" - } -) - -``` - -### 3. Test data isolation - -Ensure users never see each other's data: - -```python -# Get Mike's memories -mike_memories = mem0_client.get_all(filters={"user_id": "mike"}) - -# Get Sarah's memories -sarah_memories = mem0_client.get_all(filters={"user_id": "sarah"}) - -# Verify no overlap -assert len(set(mike_memories) & set(sarah_memories)) == 0, "Data leak detected!" - -``` - -### 4. Version your agents - -Allows A/B testing different coaching styles: - -```python -# Version 1: Gentle and encouraging -mem0_client.add( - "I'm supportive and celebrate small wins", - agent_id="fitcoach_v1" -) - -# Version 2: Data-driven and metric-focused -mem0_client.add( - "I provide concrete metrics and percentage improvements", - agent_id="fitcoach_v2" -) - -# Assign users to different versions by storing version in metadata -mem0_client.add( - "Sarah's workout preferences and relationship with coach", - user_id="sarah", - metadata={"agent_id": "fitcoach_v1"} -) -mem0_client.add( - "Mike's workout preferences and relationship with coach", - user_id="mike", - metadata={"agent_id": "fitcoach_v2"} -) - -``` - ---- - -## What You Built - -A fitness coach with three-layer memory architecture: - -- **Agent personality (agent_id)** - Shared coaching style across all users, updated once -- **User profiles (user_id)** - Private workout history, goals, and progress for each person -- **Relationship memories (user_id + metadata)** - Personalized interaction preferences per user-agent pair -- **Data isolation** - Sarah never sees Mike's workouts, guaranteed by user_id filtering - -This pattern scales from 10 to 10,000 users without duplicating agent personality. - ---- - -## Summary - -With Mem0's **`user_id`** and **`agent_id`** parameters, you can build AI agents that maintain consistent personalities across all users while remembering individual user data privately. Store relationship preferences with **`user_id`** and track agent context in metadata. - -Most apps only need **`user_id`**. Add **`agent_id`** when your AI needs a consistent personality that evolves independently from user data—fitness coaches, tutors, therapy bots, and game NPCs all fit this pattern. - - - - Filter low-signal conversations before they pollute long-term memory. - - - Categorize customer context so teams can retrieve the right facts fast. - - diff --git a/docs/cookbooks/essentials/building_ai_with_personality 295f22c70c908182affdfc87ec79f2db/image.png b/docs/cookbooks/essentials/building_ai_with_personality 295f22c70c908182affdfc87ec79f2db/image.png deleted file mode 100644 index ae5e516ac..000000000 Binary files a/docs/cookbooks/essentials/building_ai_with_personality 295f22c70c908182affdfc87ec79f2db/image.png and /dev/null differ diff --git a/docs/cookbooks/essentials/choosing-memory-architecture-vector-vs-graph.mdx b/docs/cookbooks/essentials/choosing-memory-architecture-vector-vs-graph.mdx index de3c7a65f..4e1f94139 100644 --- a/docs/cookbooks/essentials/choosing-memory-architecture-vector-vs-graph.mdx +++ b/docs/cookbooks/essentials/choosing-memory-architecture-vector-vs-graph.mdx @@ -352,8 +352,8 @@ Vector stores handle most memory operations efficiently—semantic search works The key is knowing which tool fits your query pattern: direct questions work with vectors, multi-hop relationship queries need graphs. - - Scope memories across user and agent IDs to balance personalization and reuse. + + Scope memories across users, agents, apps, and sessions to balance personalization and reuse. Learn how to migrate or audit stored memories with structured exports. diff --git a/docs/cookbooks/essentials/entity-partitioning-playbook.mdx b/docs/cookbooks/essentials/entity-partitioning-playbook.mdx new file mode 100644 index 000000000..1247a5e30 --- /dev/null +++ b/docs/cookbooks/essentials/entity-partitioning-playbook.mdx @@ -0,0 +1,332 @@ +--- +title: Partition Memories by Entity +description: Keep memories separate by tagging each write and query with user, agent, app, and session identifiers. +--- + +Nora runs a travel service. When she stored all memories in one bucket, a recruiter's nut allergy accidentally appeared in a traveler's dinner reservation. Let's fix this by properly separating memories for different users, agents, and applications. + + +**Time to complete:** ~15 minutes · **Languages:** Python + + +## Setup + +```python +from mem0 import MemoryClient + +client = MemoryClient(api_key="m0-...") +``` + +Grab an API key from the Mem0 dashboard to get started. + +## Store and Retrieve Scoped Memories + +Let's start by storing Cam's travel preferences and retrieving them: + +```python +cam_messages = [ + {"role": "user", "content": "I'm Cam. Keep in mind I avoid shellfish and prefer boutique hotels."}, + {"role": "assistant", "content": "Noted! I'll use those preferences in future itineraries."} +] + +result = client.add( + cam_messages, + user_id="traveler_cam", + agent_id="travel_planner", + run_id="tokyo-2025-weekend", + app_id="concierge_app", + version="v2" +) +``` + +The memory is now stored. Let's retrieve those memories with the same identifiers: + +```python +user_scope = { + "AND": [ + {"user_id": "traveler_cam"}, + {"app_id": "concierge_app"}, + {"run_id": "tokyo-2025-weekend"} + ] +} +user_memories = client.search("Any dietary restrictions?", filters=user_scope) +print(user_memories) + +agent_scope = { + "AND": [ + {"agent_id": "travel_planner"}, + {"app_id": "concierge_app"} + ] +} +agent_memories = client.search("Any dietary restrictions?", filters=agent_scope) +print(agent_memories) +``` + +**Output:** +``` +{'results': [{'memory': 'avoids shellfish and prefers boutique hotels', ...}]} +{'results': [{'memory': 'avoids shellfish and prefers boutique hotels', ...}]} +``` + + +Memories can be written with several identifiers, but each search resolves one entity boundary at a time. Run separate queries for user and agent scopes—just like above—rather than combining both in a single filter. + + +## When Memories Leak + +When Nora adds a chef agent, Cam's travel preferences leak into food recommendations: + +```python +chef_filters = {"AND": [{"user_id": "traveler_cam"}]} + +collision = client.search("What should I cook?", filters=chef_filters) +print(collision) +``` + +**Output:** +``` +['avoids shellfish and prefers boutique hotels', 'prefers Kyoto kaiseki dining experiences'] +``` + +The travel preferences appear because we only filtered by `user_id`. The chef agent shouldn't see hotel preferences. + +## Fix the Leak with Proper Filters + +First, let's add a memory specifically for the chef agent: + +```python +chef_memory = [ + {"role": "user", "content": "I'd like to try some authentic Kyoto cuisine."}, + {"role": "assistant", "content": "I'll remember that you prefer Kyoto kaiseki dining experiences."} +] + +client.add( + chef_memory, + user_id="traveler_cam", + agent_id="chef_recommender", + run_id="menu-planning-2025-04", + app_id="concierge_app", + version="v2" +) +``` + +Now search within the chef's scope: + +```python +safe_filters = { + "AND": [ + {"agent_id": "chef_recommender"}, + {"app_id": "concierge_app"}, + {"run_id": "menu-planning-2025-04"} + ] +} + +chef_memories = client.search("Any food alerts?", filters=safe_filters) +print(chef_memories) +``` + +**Output:** +``` +{'results': [{'memory': 'prefers Kyoto kaiseki dining experiences', ...}]} +``` + +Now the chef agent only sees its own food preferences. The hotel preferences stay with the travel agent. + +## Separate Apps with app_id + +Nora white-labels her travel service for a sports brand. Use `app_id` to keep enterprise data separate: + +```python +enterprise_filters = { + "AND": [ + {"app_id": "sports_brand_portal"}, + {"user_id": "*"}, + {"agent_id": "*"} + ] +} + +page = client.get_all(filters=enterprise_filters, page=1, page_size=10) +print([row["user_id"] for row in page["results"]]) +``` + +**Output:** +``` +['athlete_jane', 'coach_mike', 'team_admin'] +``` + + +Wildcards (`"*"` ) only match non-null values. Make sure you write memories with explicit `app_id` values. + + + +Need a deeper tour of AND vs OR, nested filters, or wildcard tricks? Check the Memory Filters v2 guide for full examples you can copy into this flow. + + +When the sports brand offboards, delete all their data: + +```python +client.delete_all(app_id="sports_brand_portal") +``` + +**Output:** +``` +{'message': 'Memories deleted successfully!'} +``` + +## Production Patterns + +```python +# Nightly audits - check all data for an app +def audit_app(app_id: str): + filters = {"AND": [{"app_id": app_id}, {"user_id": "*"}, {"agent_id": "*"}]} + return client.get_all(filters=filters, page=1, page_size=50) + +# Session cleanup - delete temporary conversations +def close_ticket(ticket_id: str, user_id: str): + client.delete_all(user_id=user_id, run_id=ticket_id) + +# Compliance exports - get all data for one tenant +export = client.get_memory_export(filters={"AND": [{"app_id": "sports_brand_portal"}]}) +``` + +## Complete Example + +Putting it all together - here's how to properly scope memories: + +```python +# Store memories with all identifiers +client.add( + [{"role": "user", "content": "I need a hotel near the conference center."}], + user_id="exec_123", + agent_id="booking_assistant", + app_id="enterprise_portal", + run_id="trip-2025-03", + version="v2" +) + +# Retrieve with the same scope +filters = { + "AND": [ + {"user_id": "exec_123"}, + {"app_id": "enterprise_portal"}, + {"run_id": "trip-2025-03"} + ] +} + +# Alternative: Use wildcards if you're not sure about some fields +# filters = { +# "AND": [ +# {"user_id": "exec_123"}, +# {"agent_id": "*"}, # Match any agent +# {"app_id": "enterprise_portal"}, +# {"run_id": "*"} # Match any run +# ] +# } + +results = client.search("Hotels near conference", filters=filters) + +# Debug: Print the filter you're using +print(f"Searching with filters: {filters}") + +# If no results, try a broader search to see what's stored +if not results["results"]: + print("No results found! Trying broader search...") + broader = client.get_all(filters={"user_id": "exec_123"}) + print(broader) + +print(results["results"][0]["memory"]) +``` + +**Output:** +``` +I need a hotel near the conference center. +``` + +## When to Use Each Identifier + +| Identifier | When to Use | Example Values | +|------------|-------------|----------------| +| `user_id` | Individual preferences that persist across all interactions | `cam_traveler`, `sarah_exec`, `team_alpha` | +| `agent_id` | Different AI roles need separate context | `travel_agent`, `concierge`, `customer_support` | +| `app_id` | White-label deployments or separate products | `travel_app_ios`, `enterprise_portal`, `partner_integration` | +| `run_id` | Temporary sessions that should be isolated | `support_ticket_9234`, `chat_session_456`, `booking_flow_789` | + +## Troubleshooting Common Issues + +### My search returns empty results! + +**Problem**: Using `AND` with exact matches but some fields might be `null`. + +**Solution**: +```python +# If this returns nothing: +filters = {"AND": [{"user_id": "u1"}, {"agent_id": "a1"}]} + +# Try using wildcards: +filters = {"AND": [{"user_id": "u1"}, {"agent_id": "*"}]} + +# Or don't include fields you don't need: +filters = {"AND": [{"user_id": "u1"}]} +``` + +### OR gives results but AND doesn't + +This confirms you have a **field mismatch**. The memory exists but some identifier values don't match exactly. + +**Always check what's actually stored:** +```python +# Get all memories for the user to see the actual field values +all_mems = client.get_all(filters={"user_id": "your_user_id"}) +print(json.dumps(all_mems, indent=2)) +``` + +## Best Practices + +1. **Use consistent identifier formats** + ```python + # Good: consistent patterns + user_id = "cam_traveler" + agent_id = "travel_agent_v1" + app_id = "nora_concierge_app" + run_id = "tokyo_trip_2025_03" + + # Avoid: mixed patterns + # user_id = "123", agent_id = "agent2", app_id = "app" + ``` + +2. **Print filters when debugging** + ```python + filters = {"AND": [{"user_id": "cam", "agent_id": "chef"}]} + print(f"Searching with filters: {filters}") # Helps catch typos + ``` + +3. **Clean up temporary sessions** + ```python + # After a support ticket closes + client.delete_all(user_id="customer_123", run_id="ticket_456") + ``` + +## Summary + +You learned how to: +- Store memories with proper entity scoping using `user_id`, `agent_id`, `app_id`, and `run_id` +- Prevent memory leaks between different agents and applications +- Clean up data for specific tenants or sessions +- Use wildcards to query across scoped memories + +## Next Steps + + + + + diff --git a/docs/cookbooks/frameworks/eliza-os-character.mdx b/docs/cookbooks/frameworks/eliza-os-character.mdx index 6afe5875a..8ec6d95cc 100644 --- a/docs/cookbooks/frameworks/eliza-os-character.mdx +++ b/docs/cookbooks/frameworks/eliza-os-character.mdx @@ -76,8 +76,8 @@ This is a simple example of how to use Mem0 to create a personalized AI agent. Y --- - - Separate agent and user memories to maintain consistent character personalities. + + Keep character personas isolated by tagging user, agent, and session identifiers. Build another type of personalized companion with memory capabilities. diff --git a/docs/cookbooks/frameworks/llamaindex-multiagent.mdx b/docs/cookbooks/frameworks/llamaindex-multiagent.mdx index 2cf37c75e..fefa2ebf1 100644 --- a/docs/cookbooks/frameworks/llamaindex-multiagent.mdx +++ b/docs/cookbooks/frameworks/llamaindex-multiagent.mdx @@ -365,7 +365,7 @@ Based on our previous session, I remember we covered Vision Language Models and Start with single-agent patterns before scaling to multi-agent systems. - - Learn how to scope memories across multiple agents and users. + + Learn how to scope memories across multiple agents, users, and sessions. diff --git a/docs/cookbooks/integrations/mastra-agent.mdx b/docs/cookbooks/integrations/mastra-agent.mdx index f512c1b76..1fa58028d 100644 --- a/docs/cookbooks/integrations/mastra-agent.mdx +++ b/docs/cookbooks/integrations/mastra-agent.mdx @@ -129,8 +129,8 @@ In the example above: --- - - Separate agent and user memories to maintain consistent personalities. + + Separate user, agent, and app memories to keep multi-agent flows clean. Explore tool-calling patterns with the OpenAI Agents SDK. diff --git a/docs/cookbooks/operations/team-task-agent.mdx b/docs/cookbooks/operations/team-task-agent.mdx index 87b7dadc3..edfeca0a3 100644 --- a/docs/cookbooks/operations/team-task-agent.mdx +++ b/docs/cookbooks/operations/team-task-agent.mdx @@ -127,8 +127,8 @@ Mem0 enables fast, transparent collaboration for teams and agents, with full att --- - - Learn how to scope memories across users and agents for team workflows. + + Learn how to scope memories across users, agents, and runs for team workflows. Apply collaborative memory patterns to customer support scenarios. diff --git a/docs/cookbooks/overview.mdx b/docs/cookbooks/overview.mdx index 9e854638b..896844ddc 100644 --- a/docs/cookbooks/overview.mdx +++ b/docs/cookbooks/overview.mdx @@ -19,8 +19,8 @@ Here are some examples of how Mem0 can be integrated into various applications: Learn core memory lifecycle patterns. - - Balance personalization with consistent behavior. + + Balance personalization with consistent behavior across users, agents, and apps. Filter speculation and low-confidence data. diff --git a/docs/docs.json b/docs/docs.json index faa9b17b8..ab9f22d91 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -63,6 +63,7 @@ "icon": "circle-check", "pages": [ "platform/features/v2-memory-filters", + "platform/features/entity-scoped-memory", "platform/features/async-client", "platform/features/async-mode-default-change", "platform/features/multimodal-support", @@ -315,7 +316,7 @@ "icon": "flag", "pages": [ "cookbooks/essentials/building-ai-companion", - "cookbooks/essentials/building-ai-with-personality", + "cookbooks/essentials/entity-partitioning-playbook", "cookbooks/essentials/controlling-memory-ingestion", "cookbooks/essentials/memory-expiration-short-and-long-term", "cookbooks/essentials/tagging-and-organizing-memories", diff --git a/docs/llms.txt b/docs/llms.txt index 0a0c9ca37..fed2454ad 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -163,7 +163,7 @@ Key differentiators: ### Essential Guides - [Building AI Companion](https://docs.mem0.ai/cookbooks/essentials/building-ai-companion): Core patterns for building AI agents with memory -- [Building AI with Personality](https://docs.mem0.ai/cookbooks/essentials/building-ai-with-personality): Creating AI agents that have distinct personalities and behaviors +- [Partition Memories by Entity](https://docs.mem0.ai/cookbooks/essentials/entity-partitioning-playbook): Keep multi-tenant assistants isolated by tagging user, agent, app, and session identifiers - [Controlling Memory Ingestion](https://docs.mem0.ai/cookbooks/essentials/controlling-memory-ingestion): Fine-tune what gets stored in memory and when - [Memory Expiration](https://docs.mem0.ai/cookbooks/essentials/memory-expiration-short-and-long-term): Implement short-term and long-term memory strategies - [Tagging and Organizing Memories](https://docs.mem0.ai/cookbooks/essentials/tagging-and-organizing-memories): Advanced memory organization and categorization diff --git a/docs/platform/features/entity-scoped-memory.mdx b/docs/platform/features/entity-scoped-memory.mdx new file mode 100644 index 000000000..4e597c197 --- /dev/null +++ b/docs/platform/features/entity-scoped-memory.mdx @@ -0,0 +1,193 @@ +--- +title: Entity-Scoped Memory +description: Scope conversations by user, agent, app, and session so memories land exactly where they belong. +--- + +Mem0's Platform API lets you separate memories for different users, agents, and apps. By tagging each write and query with the right identifiers, you can prevent data from mixing between them, maintain clear audit trails, and control data retention. + + +Want the long-form tutorial? The Partition Memories by Entity cookbook walks through multi-agent storage, debugging, and cleanup step by step. + + + + **You'll use this when…** + - You run assistants for multiple customers who each need private memory spaces + - Different agents (like a planner and a critic) need separate context for the same user + - Sessions should expire on their own schedule, making debugging and data removal more precise + + + +## Configure access +```python +from mem0 import MemoryClient + +client = MemoryClient(api_key="m0-...") +``` +Call `client.project.get()` to verify your connection. It should return your project details including `org_id` and `project_id`. If you get a 401 error, generate a new API key in the Mem0 dashboard. + +## Feature anatomy + +| Dimension | Field | When to use it | Example value | +| ----------- | ---------- | ------------------------------------------------ | ------------------- | +| User | `user_id` | Persistent persona or account | `"customer_6412"` | +| Agent | `agent_id` | Distinct agent persona or tool | `"meal_planner"` | +| Application | `app_id` | White-label app or product surface | `"ios_retail_demo"` | +| Session | `run_id` | Short-lived flow, ticket, or conversation thread | `"ticket-9241"` | + +- **Writes** (`client.add`) accept any combination of these fields. Absent fields default to `null`. +- **Reads** (`client.search`, `client.get_all`, exports, deletes) accept the same identifiers inside the `filters` JSON object. +- **Implicit null scoping**: Passing only `{"user_id": "alice"}` automatically restricts results to records where `agent_id`, `app_id`, and `run_id` are `null`. Add wildcards (`"*"`), explicit lists, or additional filters when you need broader joins. + + + **Common Pitfall**: If you create a memory with `user_id="alice"` but the other fields default to `null`, then search with `{"AND": [{"user_id": "alice"}, {"agent_id": "bot"}]}` will return nothing because you're looking for a memory where `agent_id="bot"`, not `null`. + + +## Choose the right identifier + +| Identifier | Purpose | Example Use Cases | +|------------|---------|-------------------| +| `user_id` | Store preferences, profile details, and historical actions that follow a person everywhere | Dietary restrictions, seat preferences, meeting habits | +| `agent_id` | Keep an agent's personality, operating modes, or brand voice in one place | Travel agent vs concierge vs customer support personas | +| `app_id` | Tag every write from a partner app or deployment for tenant separation | White-label deployments, partner integrations | +| `run_id` | Isolate temporary flows that should reset or expire independently | Support tickets, chat sessions, experiments | + +For more detailed examples, see the Partition Memories by Entity cookbook. + +## Configure it + +The example below adds memories with entity tags: +```python +messages = [ + {"role": "user", "content": "I teach ninth-grade algebra."}, + {"role": "assistant", "content": "I'll tailor study plans to algebra topics."} +] + +client.add( + messages, + user_id="teacher_872", + agent_id="study_planner", + app_id="district_dashboard", + run_id="prep-period-2025-09-02", + version="v2" +) +``` + +The response will include one or more memory IDs. Check the dashboard → Memories to confirm the entry appears under the correct user, agent, app, and run. + +The HTTP equivalent uses `POST /v1/memories/` with the same identifiers in the JSON body. See the Add Memories API reference for REST details. + +## See it in action + +**1. Store scoped memories** +```python +traveler_messages = [ + {"role": "user", "content": "I prefer boutique hotels and avoid shellfish."}, + {"role": "assistant", "content": "Logged your travel preferences for future itineraries."} +] + +client.add( + traveler_messages, + user_id="customer_6412", + agent_id="travel_planner", + app_id="concierge_portal", + run_id="itinerary-2025-apr", + metadata={"category": "preferences"}, + version="v2" +) +``` + +**2. Retrieve by user scope** +```python +user_scope = { + "AND": [ + {"user_id": "customer_6412"}, + {"app_id": "concierge_portal"}, + {"run_id": "itinerary-2025-apr"} + ] +} + +user_results = client.search("Any dietary flags?", filters=user_scope) +print(user_results) +``` + +**3. Retrieve by agent scope** +```python +agent_scope = { + "AND": [ + {"agent_id": "travel_planner"}, + {"app_id": "concierge_portal"} + ] +} + +agent_results = client.search("Any dietary flags?", filters=agent_scope) +print(agent_results) +``` + + +Writes can include multiple identifiers, but searches resolve one entity space at a time. Query user scope *or* agent scope in a given call—combining both returns an empty list today. + + + +Want to experiment with AND/OR logic, nested operators, or wildcards? The Memory Filters v2 guide walks through every filter pattern with working examples. + + +**4. Audit everything for an app** +```python +app_scope = { + "AND": [ + {"app_id": "concierge_portal"}, + {"user_id": "*"}, + {"agent_id": "*"} + ] +} + +page = client.get_all(filters=app_scope, page=1, page_size=20) +``` + + +Wildcards (`"*"`) include only non-null values. Use them when you want "any agent" or "any user" without limiting results to null-only records. + + +**5. Clean up a session** +```python +client.delete_all( + user_id="customer_6412", + run_id="itinerary-2025-apr" +) +``` + + +A successful delete returns `{"message": "Memories deleted successfully!"}`. Run the previous `get_all` call again to confirm the session memories were removed. + + +## Verify the feature is working + +- Run `client.search` with your filters and confirm only expected memories appear. Mismatched identifiers usually mean a typo in your scoping. +- Check the Mem0 dashboard filter pills. User, agent, app, and run should all show populated values for your memory entry. +- Call `client.delete_all` with a unique `run_id` and confirm other sessions remain intact (the count in `get_all` should only drop for that run). + +## Best practices + +- Use consistent identifier formats (like `team-alpha` or `app-ios-retail`) so you can query or delete entire groups later +- When debugging, print your filters before each call to verify wildcards (`"*"`), lists, and run IDs are spelled correctly +- Combine entity filters with metadata filters (categories, created_at) for precise exports or audits +- Use `run_id` for temporary sessions like support tickets or experiments, then schedule cleanup jobs to delete them + +For a complete walkthrough, see the Partition Memories by Entity cookbook. + +{/* DEBUG: verify CTA targets */} + + + + +