789122bbea
The Python sync/async MemoryClient and the TS MemoryClient were silently switching their PostHog distinct_id from an anonymous on-disk UUID to the user's email post-ping, without sending the merge instruction. PostHog ended up tracking each user as 2-3 disconnected personas (OSS UUID, CLI anon UUID, email), and only ~4 $create_alias events fired across ~300K users. The Python CLI does this correctly today; this change ports the same pattern to MemoryClient. - mem0/memory/setup.py: make setup_config() idempotent so it backfills a top-level user_id for CLI-first users (the CLI writes telemetry.anonymous_id, not user_id, which left OSS telemetry silently dropped). Add read_anon_ids() and mark_aliased() helpers. - mem0/memory/telemetry.py: add AnonymousTelemetry.capture_identify() that posts a PostHog $identify event with $anon_distinct_id. Add "$identify" to _LIFECYCLE_EVENTS so it bypasses the 90% sampling drop. - mem0/client/main.py: at the end of __init__ for both MemoryClient and AsyncMemoryClient, fire $identify for each unaliased anon ID and persist telemetry.aliased_to so the alias only happens once per (anon_id, email) pair, ever. All telemetry calls swallow exceptions. - mem0-ts/src/client/telemetry.ts: mirror with captureIdentify(). - mem0-ts/src/client/config.ts (new): node-only readMem0AnonIds() and markMem0Aliased() using async dynamic imports of fs/path/os, gated on process.versions.node so browsers no-op cleanly. - mem0-ts/src/client/mem0.ts: call _maybeAliasAnonToEmail() inside _initializeClient after ping resolves the email. Tests cover the matrix (OSS-only, CLI-only, both, already-aliased) plus failure modes (malformed JSON, read-only fs, posthog errors, browser env). Telemetry never raises.