From 3297ec1a46738e3f4170c1efa33f944404ca283b Mon Sep 17 00:00:00 2001 From: Parth Sharma <109902593+parthshr370@users.noreply.github.com> Date: Thu, 13 Nov 2025 23:56:41 +0530 Subject: [PATCH] [doc] Partition Memories by Entity , features doc and cookbook (#3735) --- .../cookbooks/companions/nodejs-companion.mdx | 4 +- .../essentials/building-ai-companion.mdx | 4 +- .../building-ai-with-personality.mdx | 603 ------------------ .../image.png | Bin 71066 -> 0 bytes ...ng-memory-architecture-vector-vs-graph.mdx | 4 +- .../entity-partitioning-playbook.mdx | 332 ++++++++++ .../frameworks/eliza-os-character.mdx | 4 +- .../frameworks/llamaindex-multiagent.mdx | 4 +- docs/cookbooks/integrations/mastra-agent.mdx | 4 +- docs/cookbooks/operations/team-task-agent.mdx | 4 +- docs/cookbooks/overview.mdx | 4 +- docs/docs.json | 3 +- docs/llms.txt | 2 +- .../features/entity-scoped-memory.mdx | 193 ++++++ 14 files changed, 544 insertions(+), 621 deletions(-) delete mode 100644 docs/cookbooks/essentials/building-ai-with-personality.mdx delete mode 100644 docs/cookbooks/essentials/building_ai_with_personality 295f22c70c908182affdfc87ec79f2db/image.png create mode 100644 docs/cookbooks/essentials/entity-partitioning-playbook.mdx create mode 100644 docs/platform/features/entity-scoped-memory.mdx 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 ae5e516ac5f6923d284a3d72075c123a93420882..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71066 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 - - 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 */} + + + + +