fix(plugin): deterministic mem0 user_id resolution
Hooks previously fell back to $USER when MEM0_USER_ID wasn't set,
producing a different user_id on every machine for the same person.
Result: a single account with memories scattered across many user
buckets, none of which can see each other.
Resolution priority (same in bash and python):
1. MEM0_USER_ID env var (explicit override)
2. ~/.mem0/identity.json cache (pinned to MEM0_API_KEY fingerprint)
3. Derived: "mem0-" + sha256(MEM0_API_KEY)[:12]
4. Fallback: $USER, else "default"
Same MEM0_API_KEY across machines now yields the same user_id without
the user having to set MEM0_USER_ID by hand on every laptop.
Resolver shipped as two tiny files instead of a shared module:
_identity.sh -- sourced by bash hooks, exports MEM0_RESOLVED_USER_ID
_identity.py -- imported by on_pre_compact.py, exposes resolve_user_id()
Hook integration:
on_user_prompt.sh -- sources resolver, USER_ID interpolated into rubric
on_session_start.sh -- emits an "Active user_id: <X>" header before the
bootstrap text, so the agent's MCP search_memories/add_memory calls
use the same bucket the hooks write to (closes the agent-side half
of the symptom)
on_pre_compact.py -- replaces inline env lookup with resolve_user_id()
Existing memories under previous $USER values are not auto-migrated.
The cache file regenerates on key rotation (fingerprint mismatch).
This commit is contained in:
@@ -18,8 +18,11 @@ import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from _identity import resolve_user_id
|
||||
|
||||
log = logging.getLogger("mem0-capture")
|
||||
log.setLevel(logging.DEBUG)
|
||||
@@ -219,7 +222,7 @@ def main():
|
||||
return
|
||||
|
||||
session_id = hook_input.get("session_id", "")
|
||||
user_id = os.environ.get("MEM0_USER_ID", os.environ.get("USER", "default"))
|
||||
user_id = resolve_user_id()
|
||||
|
||||
lines = tail_lines(transcript_path, MAX_TAIL_LINES)
|
||||
if not lines:
|
||||
|
||||
Reference in New Issue
Block a user