repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | --- |
| #2 | title: Partition Memories by Entity |
| #3 | description: Keep memories separate by tagging each write and query with user, agent, app, and session identifiers. |
| #4 | --- |
| #5 | |
| #6 | 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. |
| #7 | |
| #8 | <Info icon="clock"> |
| #9 | **Time to complete:** ~15 minutes · **Languages:** Python |
| #10 | </Info> |
| #11 | |
| #12 | ## Setup |
| #13 | |
| #14 | ```python |
| #15 | from mem0 import MemoryClient |
| #16 | |
| #17 | client = MemoryClient(api_key="m0-...") |
| #18 | ``` |
| #19 | |
| #20 | Grab an API key from the <Link href="https://app.mem0.ai/">Mem0 dashboard</Link> to get started. |
| #21 | |
| #22 | ## Store and Retrieve Scoped Memories |
| #23 | |
| #24 | Let's start by storing Cam's travel preferences and retrieving them: |
| #25 | |
| #26 | ```python |
| #27 | cam_messages = [ |
| #28 | {"role": "user", "content": "I'm Cam. Keep in mind I avoid shellfish and prefer boutique hotels."}, |
| #29 | {"role": "assistant", "content": "Noted! I'll use those preferences in future itineraries."} |
| #30 | ] |
| #31 | |
| #32 | result = client.add( |
| #33 | cam_messages, |
| #34 | user_id="traveler_cam", |
| #35 | agent_id="travel_planner", |
| #36 | run_id="tokyo-2025-weekend", |
| #37 | app_id="concierge_app" |
| #38 | ) |
| #39 | ``` |
| #40 | |
| #41 | The memory is now stored. Let's retrieve those memories with the same identifiers: |
| #42 | |
| #43 | ```python |
| #44 | user_scope = { |
| #45 | "AND": [ |
| #46 | {"user_id": "traveler_cam"}, |
| #47 | {"app_id": "concierge_app"}, |
| #48 | {"run_id": "tokyo-2025-weekend"} |
| #49 | ] |
| #50 | } |
| #51 | user_memories = client.search("Any dietary restrictions?", filters=user_scope) |
| #52 | print(user_memories) |
| #53 | |
| #54 | agent_scope = { |
| #55 | "AND": [ |
| #56 | {"agent_id": "travel_planner"}, |
| #57 | {"app_id": "concierge_app"} |
| #58 | ] |
| #59 | } |
| #60 | agent_memories = client.search("Any dietary restrictions?", filters=agent_scope) |
| #61 | print(agent_memories) |
| #62 | ``` |
| #63 | |
| #64 | **Output:** |
| #65 | ``` |
| #66 | # User scope returns user's memory |
| #67 | {'results': [{'memory': 'avoids shellfish and prefers boutique hotels', ...}]} |
| #68 | # Agent scope returns agent's own memory |
| #69 | {'results': [{'memory': 'Cam prefers boutique hotels and avoids shellfish', ...}]} |
| #70 | ``` |
| #71 | |
| #72 | <Tip icon="compass"> |
| #73 | 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. |
| #74 | </Tip> |
| #75 | |
| #76 | ## When Memories Leak |
| #77 | |
| #78 | When Nora adds a chef agent, Cam's travel preferences leak into food recommendations: |
| #79 | |
| #80 | ```python |
| #81 | chef_filters = {"AND": [{"user_id": "traveler_cam"}]} |
| #82 | |
| #83 | collision = client.search("What should I cook?", filters=chef_filters) |
| #84 | print(collision) |
| #85 | ``` |
| #86 | |
| #87 | **Output:** |
| #88 | ``` |
| #89 | ['avoids shellfish and prefers boutique hotels', 'prefers Kyoto kaiseki dining experiences'] |
| #90 | ``` |
| #91 | |
| #92 | The travel preferences appear because we only filtered by `user_id`. The chef agent shouldn't see hotel preferences. |
| #93 | |
| #94 | ## Fix the Leak with Proper Filters |
| #95 | |
| #96 | First, let's add a memory specifically for the chef agent: |
| #97 | |
| #98 | ```python |
| #99 | chef_memory = [ |
| #100 | {"role": "user", "content": "I'd like to try some authentic Kyoto cuisine."}, |
| #101 | {"role": "assistant", "content": "I'll remember that you prefer Kyoto kaiseki dining experiences."} |
| #102 | ] |
| #103 | |
| #104 | client.add( |
| #105 | chef_memory, |
| #106 | user_id="traveler_cam", |
| #107 | agent_id="chef_recommender", |
| #108 | run_id="menu-planning-2025-04", |
| #109 | app_id="concierge_app" |
| #110 | ) |
| #111 | ``` |
| #112 | |
| #113 | Now search within the chef's scope: |
| #114 | |
| #115 | ```python |
| #116 | safe_filters = { |
| #117 | "AND": [ |
| #118 | {"agent_id": "chef_recommender"}, |
| #119 | {"app_id": "concierge_app"}, |
| #120 | {"run_id": "menu-planning-2025-04"} |
| #121 | ] |
| #122 | } |
| #123 | |
| #124 | chef_memories = client.search("Any food alerts?", filters=safe_filters) |
| #125 | print(chef_memories) |
| #126 | ``` |
| #127 | |
| #128 | **Output:** |
| #129 | ``` |
| #130 | {'results': [{'memory': 'prefers Kyoto kaiseki dining experiences', ...}]} |
| #131 | ``` |
| #132 | |
| #133 | Now the chef agent only sees its own food preferences. The hotel preferences stay with the travel agent. |
| #134 | |
| #135 | ## Separate Apps with app_id |
| #136 | |
| #137 | Nora white-labels her travel service for a sports brand. Use `app_id` to keep enterprise data separate: |
| #138 | |
| #139 | ```python |
| #140 | enterprise_filters = { |
| #141 | "AND": [ |
| #142 | {"app_id": "sports_brand_portal"} |
| #143 | ], |
| #144 | "OR": [ |
| #145 | {"user_id": "*"}, |
| #146 | {"agent_id": "*"} |
| #147 | ] |
| #148 | } |
| #149 | |
| #150 | page = client.get_all(filters=enterprise_filters, page=1, page_size=10) |
| #151 | print([row["user_id"] for row in page["results"]]) |
| #152 | ``` |
| #153 | |
| #154 | **Output:** |
| #155 | ``` |
| #156 | ['athlete_jane', 'coach_mike', 'team_admin'] |
| #157 | ``` |
| #158 | |
| #159 | <Info> |
| #160 | Wildcards (`"*"` ) only match non-null values. Make sure you write memories with explicit `app_id` values. |
| #161 | </Info> |
| #162 | |
| #163 | <Tip icon="sparkles"> |
| #164 | Need a deeper tour of AND vs OR, nested filters, or wildcard tricks? Check the <Link href="/platform/features/v2-memory-filters">Memory Filters v2 guide</Link> for full examples you can copy into this flow. |
| #165 | </Tip> |
| #166 | |
| #167 | When the sports brand offboards, delete all their data: |
| #168 | |
| #169 | ```python |
| #170 | client.delete_all(app_id="sports_brand_portal") |
| #171 | ``` |
| #172 | |
| #173 | **Output:** |
| #174 | ``` |
| #175 | {'message': 'Memories deleted successfully!'} |
| #176 | ``` |
| #177 | |
| #178 | ## Production Patterns |
| #179 | |
| #180 | ```python |
| #181 | # Nightly audits - check all data for an app |
| #182 | def audit_app(app_id: str): |
| #183 | filters = { |
| #184 | "AND": [{"app_id": app_id}], |
| #185 | "OR": [{"user_id": "*"}, {"agent_id": "*"}] |
| #186 | } |
| #187 | return client.get_all(filters=filters, page=1, page_size=50) |
| #188 | |
| #189 | # Session cleanup - delete temporary conversations |
| #190 | def close_ticket(ticket_id: str, user_id: str): |
| #191 | client.delete_all(user_id=user_id, run_id=ticket_id) |
| #192 | |
| #193 | # Compliance exports - get all data for one tenant |
| #194 | export = client.get_memory_export(filters={"AND": [{"app_id": "sports_brand_portal"}]}) |
| #195 | ``` |
| #196 | |
| #197 | ## Complete Example |
| #198 | |
| #199 | Putting it all together - here's how to properly scope memories: |
| #200 | |
| #201 | ```python |
| #202 | # Store memories with all identifiers |
| #203 | client.add( |
| #204 | [{"role": "user", "content": "I need a hotel near the conference center."}], |
| #205 | user_id="exec_123", |
| #206 | agent_id="booking_assistant", |
| #207 | app_id="enterprise_portal", |
| #208 | run_id="trip-2025-03" |
| #209 | ) |
| #210 | |
| #211 | # Retrieve with the same scope |
| #212 | filters = { |
| #213 | "AND": [ |
| #214 | {"user_id": "exec_123"}, |
| #215 | {"app_id": "enterprise_portal"}, |
| #216 | {"run_id": "trip-2025-03"} |
| #217 | ] |
| #218 | } |
| #219 | |
| #220 | # Alternative: Use wildcards if you're not sure about some fields |
| #221 | # filters = { |
| #222 | # "AND": [ |
| #223 | # {"user_id": "exec_123"}, |
| #224 | # {"agent_id": "*"}, # Match any agent |
| #225 | # {"app_id": "enterprise_portal"}, |
| #226 | # {"run_id": "*"} # Match any run |
| #227 | # ] |
| #228 | # } |
| #229 | |
| #230 | results = client.search("Hotels near conference", filters=filters) |
| #231 | |
| #232 | # Debug: Print the filter you're using |
| #233 | print(f"Searching with filters: {filters}") |
| #234 | |
| #235 | # If no results, try a broader search to see what's stored |
| #236 | if not results["results"]: |
| #237 | print("No results found! Trying broader search...") |
| #238 | broader = client.get_all(filters={"user_id": "exec_123"}) |
| #239 | print(broader) |
| #240 | |
| #241 | print(results["results"][0]["memory"]) |
| #242 | ``` |
| #243 | |
| #244 | **Output:** |
| #245 | ``` |
| #246 | I need a hotel near the conference center. |
| #247 | ``` |
| #248 | |
| #249 | ## When to Use Each Identifier |
| #250 | |
| #251 | | Identifier | When to Use | Example Values | |
| #252 | |------------|-------------|----------------| |
| #253 | | `user_id` | Individual preferences that persist across all interactions | `cam_traveler`, `sarah_exec`, `team_alpha` | |
| #254 | | `agent_id` | Different AI roles need separate context | `travel_agent`, `concierge`, `customer_support` | |
| #255 | | `app_id` | White-label deployments or separate products | `travel_app_ios`, `enterprise_portal`, `partner_integration` | |
| #256 | | `run_id` | Temporary sessions that should be isolated | `support_ticket_9234`, `chat_session_456`, `booking_flow_789` | |
| #257 | |
| #258 | ## Troubleshooting Common Issues |
| #259 | |
| #260 | ### My search returns empty results! |
| #261 | |
| #262 | **Problem**: Using `AND` with exact matches but some fields might be `null`. |
| #263 | |
| #264 | **Solution**: |
| #265 | ```python |
| #266 | # If this returns nothing: |
| #267 | filters = {"AND": [{"user_id": "u1"}, {"agent_id": "a1"}]} |
| #268 | |
| #269 | # Try using wildcards: |
| #270 | filters = {"AND": [{"user_id": "u1"}, {"agent_id": "*"}]} |
| #271 | |
| #272 | # Or don't include fields you don't need: |
| #273 | filters = {"AND": [{"user_id": "u1"}]} |
| #274 | ``` |
| #275 | |
| #276 | ### OR gives results but AND doesn't |
| #277 | |
| #278 | This confirms you have a **field mismatch**. The memory exists but some identifier values don't match exactly. |
| #279 | |
| #280 | **Always check what's actually stored:** |
| #281 | ```python |
| #282 | # Get all memories for the user to see the actual field values |
| #283 | all_mems = client.get_all(filters={"user_id": "your_user_id"}) |
| #284 | print(json.dumps(all_mems, indent=2)) |
| #285 | ``` |
| #286 | |
| #287 | ## Best Practices |
| #288 | |
| #289 | 1. **Use consistent identifier formats** |
| #290 | ```python |
| #291 | # Good: consistent patterns |
| #292 | user_id = "cam_traveler" |
| #293 | agent_id = "travel_agent_v1" |
| #294 | app_id = "nora_concierge_app" |
| #295 | run_id = "tokyo_trip_2025_03" |
| #296 | |
| #297 | # Avoid: mixed patterns |
| #298 | # user_id = "123", agent_id = "agent2", app_id = "app" |
| #299 | ``` |
| #300 | |
| #301 | 2. **Print filters when debugging** |
| #302 | ```python |
| #303 | filters = {"AND": [{"user_id": "cam", "agent_id": "chef"}]} |
| #304 | print(f"Searching with filters: {filters}") # Helps catch typos |
| #305 | ``` |
| #306 | |
| #307 | 3. **Clean up temporary sessions** |
| #308 | ```python |
| #309 | # After a support ticket closes |
| #310 | client.delete_all(user_id="customer_123", run_id="ticket_456") |
| #311 | ``` |
| #312 | |
| #313 | ## Summary |
| #314 | |
| #315 | You learned how to: |
| #316 | - Store memories with proper entity scoping using `user_id`, `agent_id`, `app_id`, and `run_id` |
| #317 | - Prevent memory leaks between different agents and applications |
| #318 | - Clean up data for specific tenants or sessions |
| #319 | - Use wildcards to query across scoped memories |
| #320 | |
| #321 | ## Next Steps |
| #322 | |
| #323 | <CardGroup cols={2}> |
| #324 | <Card |
| #325 | title="Deep Dive: Memory Filters v2" |
| #326 | description="Layer entity filters with JSON logic to answer complex queries." |
| #327 | icon="sliders" |
| #328 | href="/platform/features/v2-memory-filters" |
| #329 | /> |
| #330 | <Card |
| #331 | title="Control Memory Ingestion" |
| #332 | description="Pair scoped storage with rules that block low-quality facts." |
| #333 | icon="shield-check" |
| #334 | href="/cookbooks/essentials/controlling-memory-ingestion" |
| #335 | /> |
| #336 | </CardGroup> |
| #337 |