Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db5524d0db | ||
|
|
9d82e2329d | ||
|
|
789cc9d607 | ||
|
|
e59e3d5f0c | ||
|
|
d926f3697c | ||
|
|
c996b0e7fa |
@@ -10,7 +10,7 @@ description: "REST APIs for memory management, search, and entity operations"
|
||||
Mem0 provides a comprehensive REST API for integrating advanced memory capabilities into your applications. Create, search, update, and manage memories across users, agents, and custom entities with simple HTTP requests.
|
||||
|
||||
<Info>
|
||||
**Quick start:** Get your API key from the [Mem0 Dashboard](https://app.mem0.ai/dashboard/api-keys) and make your first memory operation in minutes.
|
||||
**Quick start:** Get your API key from the <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 Dashboard</a> and make your first memory operation in minutes.
|
||||
</Info>
|
||||
|
||||
---
|
||||
@@ -87,7 +87,7 @@ All API requests require authentication using Token-based authentication. Includ
|
||||
Authorization: Token <your-api-key>
|
||||
```
|
||||
|
||||
Get your API key from the [Mem0 Dashboard](https://app.mem0.ai/dashboard/api-keys).
|
||||
Get your API key from the <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 Dashboard</a>.
|
||||
|
||||
<Warning>
|
||||
**Keep your API key secure.** Never expose it in client-side code or public repositories. Use environment variables and server-side requests only.
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
---
|
||||
title: "Highlights"
|
||||
description: "Major product launches, headline features, and milestones for Mem0."
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Update label="2026-04-06" description="Mem0 Skill Graph">
|
||||
|
||||
**Mem0 Skill Graph — In-Context Documentation for AI Agents**
|
||||
|
||||
AI coding agents in Claude Code, Cursor, and Codex can now access Mem0 knowledge directly in their workflow — no doc searching required. Three interconnected skills launched:
|
||||
|
||||
- **mem0 Core Skill** — Complete Python and TypeScript SDK reference, REST API patterns, and integration guides for LangChain, CrewAI, Autogen, and more
|
||||
- **mem0-cli Skill** — Terminal command reference, configuration walkthroughs, and CI/CD recipes
|
||||
- **mem0-vercel-ai-sdk Skill** — Vercel AI SDK provider API, memory-augmented generation patterns, and multi-provider setup
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-06" description="Mem0 CLI v0.2.2">
|
||||
|
||||
**Official Mem0 CLI — Now on PyPI and npm**
|
||||
|
||||
A full-featured command-line interface for Mem0, available in both Python and Node.js:
|
||||
|
||||
- **Install:** `pip install mem0-cli` or `npm install -g @mem0/cli`
|
||||
- **Full command suite** — `add`, `search`, `list`, `get`, `update`, `delete`, `import`, `config`, `init`, `status`, `entity`, `event`
|
||||
- **Interactive setup** — `mem0 init` with email verification or direct API key entry
|
||||
- **Works everywhere** — Platform (Mem0 Cloud) and self-hosted OSS modes
|
||||
- **Scriptable** — `--json` flag for CI/CD pipelines and automation
|
||||
- **Dual SDK** — Same commands, same experience across Python and Node.js
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-04" description="OpenClaw v1.0.4">
|
||||
|
||||
**OpenClaw Plugin — Production-Ready**
|
||||
|
||||
The OpenClaw Mem0 plugin went from initial release to production-ready in one week (v1.0.0 → v1.0.4):
|
||||
|
||||
- **Skills-based memory architecture** — New extraction pipeline with skill-loader, batched extraction, and domain-aware memory triage
|
||||
- **Dream gate** — Automatic memory consolidation during idle periods for higher-quality long-term recall
|
||||
- **Interactive CLI** — `openclaw mem0 init`, `status`, `config`, `import`, and `event` commands
|
||||
- **Unified tool naming** — `memory_add` and `memory_delete` replace 4 legacy tools, matching the platform API
|
||||
- **Security hardened** — Path traversal protection, pinned dependencies, 329 tests across 10 files
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-02" description="Mem0 Plugin for AI Editors">
|
||||
|
||||
**Mem0 Plugin for Claude Code, Cursor, and Codex**
|
||||
|
||||
Launched a unified Mem0 plugin across three major AI development environments — Claude Code and Cursor first (March 25), then Codex (April 2):
|
||||
|
||||
- **9 MCP memory tools** — add, search, get, update, delete, bulk delete, entity management via `mcp.mem0.ai`
|
||||
- **Lifecycle hooks** — Automatic memory capture at session start, context compaction, task completion, and session end
|
||||
- **Cloud MCP server** — Managed endpoint replaces local MCP and Smithery setup
|
||||
- **Streamable HTTP transport** — New MCP transport protocol for real-time streaming
|
||||
- **Codex-specific skill** — Dedicated skill in `mem0-plugin/skills/mem0-codex` for Codex workflows
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-03-21" description="New Providers">
|
||||
|
||||
**Apache AGE, Turbopuffer, MiniMax, and pgvector for Node.js**
|
||||
|
||||
Major expansion of the provider ecosystem:
|
||||
|
||||
- **Apache AGE** — New graph store support, bringing the total to 4 graph store backends (Neo4j, Memgraph, Kuzu, Apache AGE)
|
||||
- **Turbopuffer** — New vector database provider for Python SDK
|
||||
- **MiniMax** — New LLM provider with dedicated AWS Bedrock support
|
||||
- **pgvector for Node.js** — PostgreSQL vector support added to the TypeScript OSS SDK
|
||||
- **Reasoning models** — `reasoning_effort` parameter for OpenAI o1/o3-style models
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-03-14" description="Mem0 Platform Skill">
|
||||
|
||||
**Mem0 Platform Skill on skills.sh**
|
||||
|
||||
First skill launch — a dedicated Mem0 skill providing platform API reference, quickstart patterns, and integration examples directly inside agent sessions. Available on [skills.sh](https://skills.sh) for any compatible AI coding agent.
|
||||
|
||||
</Update>
|
||||
@@ -0,0 +1,185 @@
|
||||
---
|
||||
title: "OpenClaw"
|
||||
description: "Release notes for the OpenClaw plugin and agent harness."
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Update label="2026-04-07" description="v1.0.5">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Init interactive choice bug**: Fixed number selection in `openclaw mem0 init` — entering 1/2/3 now correctly selects the corresponding option (was broken by readline prefill concatenating with user input)
|
||||
- **OSS pgvector crash** ([#4727](https://github.com/mem0ai/mem0/issues/4727)): Fixed "Client has already been connected" cascade when using pgvector in OSS mode. The warmup call swallowed errors leaving a half-initialized pg client; concurrent recall/capture then all hit `client.connect()` on the same client. Fix: let warmup errors propagate (so `initPromise` resets and retries with a fresh Memory + fresh pg client) and build fresh config objects per attempt instead of mutating shared state.
|
||||
|
||||
**Removed:**
|
||||
- **`orgId` / `projectId` config parameters**: Removed from config schema, CLI (`config show/get/set`), init display, and providers. The API key is project-scoped, so separate org/project IDs are unnecessary and could cause access errors if mismatched.
|
||||
- **`enableGraph` config parameter**: Removed from all config surfaces, providers, backend, and tools. Graph memory is being deprecated — removing the flag avoids unnecessary exposure.
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-04" description="v1.0.4">
|
||||
|
||||
**New Features:**
|
||||
- **Interactive init flow**: `openclaw mem0 init` with interactive menu (email verification or direct API key). Non-interactive modes: `--api-key`, `--email`, `--email --code`
|
||||
- **`memory_add` tool**: Replaces `memory_store` — name now matches `mem0` CLI and platform API
|
||||
- **`memory_delete` tool**: Unified delete — single ID, search-then-delete, bulk, entity cascade. Replaces `memory_forget` and `memory_delete_all`
|
||||
- **CLI subcommands**: `openclaw mem0 init`, `openclaw mem0 status`, `openclaw mem0 config show`, `openclaw mem0 config set`
|
||||
- **`import` CLI command**: Bulk-import memories from a JSON file with `--user-id` and `--agent-id` overrides
|
||||
- **`event list` / `event status` CLI commands**: Monitor background processing events
|
||||
- **`fs-safe.ts` module**: Isolated filesystem wrappers in a separate entry point
|
||||
- **`backend/` module**: `PlatformBackend` with direct HTTP API access for CLI commands
|
||||
- **Plugin manifest**: Added `contracts.tools`, `configSchema`, and `uiHints` to `openclaw.plugin.json`
|
||||
- **Test suite**: 329 tests across 10 test files
|
||||
|
||||
**Changes:**
|
||||
- **Modular architecture**: Extracted tools into `tools/` directory (6 files) and CLI into `cli/commands.ts`
|
||||
- **Code splitting**: tsup builds with `splitting: true` and two entry points
|
||||
- **Skills updated**: All SKILL.md files reference new tool names (`memory_add`, `memory_delete`)
|
||||
- **Auto-recall timeout**: Recall wrapped in 8-second `Promise.race`
|
||||
- **Auto-capture fire-and-forget**: `provider.add()` runs in background via `.then()/.catch()`
|
||||
- **Auto-capture minimum content gate**: Skips extraction when total user content is fewer than 50 chars
|
||||
|
||||
**Removed:**
|
||||
- `memory_store` tool — replaced by `memory_add`
|
||||
- `memory_forget` tool — replaced by `memory_delete`
|
||||
- `memory_delete_all` tool — merged into `memory_delete`
|
||||
- `memory_history` tool and `history` CLI command — deprecated
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-03" description="v1.0.3">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Security**: Added `safePath()` containment helper to `readSkillFile` and `readDomainOverlay` in `skill-loader.ts` — prevents directory traversal
|
||||
- **Noise filter**: Reverted incorrect `After-Compaction` regex rename back to `Post-Compaction`
|
||||
|
||||
**Changes:**
|
||||
- **Supply-chain hardening**: Pinned `mem0ai` dependency to exact `2.3.0` (was `^2.3.0`)
|
||||
|
||||
**Tests:**
|
||||
- 12 new tests covering `safePath`, `readSkillFile`, `readDomainOverlay`, and `loadSkill` with traversal inputs
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-02" description="v1.0.2">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Security**: Removed `resolveEnvVars()` and `resolveEnvVarsDeep()` from `config.ts` — plugin-side env resolution was redundant and triggered static analysis warnings ([#4676](https://github.com/mem0ai/mem0/pull/4676))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-02" description="v1.0.1">
|
||||
|
||||
**New Features:**
|
||||
- **CD workflow**: Added continuous deployment workflow with OIDC trusted publishing ([#4672](https://github.com/mem0ai/mem0/pull/4672))
|
||||
- **Plugin configuration manifest**: Added `compat` and `build` metadata to `package.json` ([#4667](https://github.com/mem0ai/mem0/pull/4667))
|
||||
- **LICENSE**: Added Apache-2.0 license file ([#4667](https://github.com/mem0ai/mem0/pull/4667))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Dream gate**: Fixed cheap-first ordering, session isolation, and verified completion ([#4666](https://github.com/mem0ai/mem0/pull/4666))
|
||||
- **Graceful startup**: Plugin now starts gracefully when no API key is configured ([#4669](https://github.com/mem0ai/mem0/pull/4669))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-01" description="v1.0.0">
|
||||
|
||||
**New Features:**
|
||||
- **Skills-based memory architecture**: New skill-loader and skill-based extraction pipeline with batched extraction ([#4624](https://github.com/mem0ai/mem0/pull/4624))
|
||||
- **Dream gate**: Memory consolidation and dream-cycle processing during idle periods
|
||||
- **Enhanced recall**: New `recall.ts` module with improved recall logic and skill-aware retrieval
|
||||
- **Memory triage skill**: Domain-aware memory triage with companion domain support and recall protocol
|
||||
- **Memory dream skill**: Skill for memory consolidation during idle periods
|
||||
- **Plugin configuration**: Added `openclaw.plugin.json` manifest and `scripts/configure.py` setup helper
|
||||
|
||||
**Changes:**
|
||||
- Extraction pipeline refactored to use skills-based architecture for more contextual and higher quality memory capture
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-03-26" description="v0.4.1">
|
||||
|
||||
**New Features:**
|
||||
- **Improved extraction quality**: Enhanced noise filtering, deduplication, and better extraction instructions
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Credential detection**: Improved detection of credentials, API keys, and secrets in extraction instructions (#4552)
|
||||
- **Standalone timestamps**: Prevented extraction of standalone timestamps as memories (#4550)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-03-16" description="v0.4.0">
|
||||
|
||||
**New Features:**
|
||||
- **Non-interactive trigger filtering**: Skips recall and capture for `cron`, `heartbeat`, `automation`, and `schedule` triggers
|
||||
- **Subagent hallucination prevention**: Detects ephemeral subagent sessions and routes recall to parent namespace
|
||||
- **Dynamic recall thresholding**: Memories scoring less than 50% of top result are dropped
|
||||
- **SQLite resilience**: Init error recovery with automatic retry for OSS mode
|
||||
- **`disableHistory` config option**: New `oss.disableHistory` flag
|
||||
- 78 unit tests covering filtering, isolation, trigger filtering, subagent detection, and SQLite resilience
|
||||
|
||||
**Changes:**
|
||||
- Auto-recall threshold raised from 0.5 to 0.6 for stricter precision
|
||||
- Recall candidate pool increased to `topK * 2` for better filtering headroom
|
||||
- Relaxed extraction instructions: related facts kept together to preserve context
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Concurrent session race condition**: Lifecycle hooks now use `ctx.sessionKey` directly instead of a shared mutable variable
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-03-12" description="v0.3.1">
|
||||
|
||||
**New Features:**
|
||||
- **Message filtering pipeline**: Multi-stage noise removal before extraction
|
||||
- **Broad recall for new sessions**: Short or new-session prompts trigger secondary broad search
|
||||
- **Client-side threshold filtering**: Safety net that drops low-relevance results
|
||||
- **Temporal anchoring**: Extraction instructions now include current date
|
||||
- 55 unit tests covering filtering and isolation helpers
|
||||
|
||||
**Changes:**
|
||||
- Extraction window expanded from last 10 to last 20 messages
|
||||
- Rewritten custom extraction instructions for conciseness and deduplication
|
||||
- Refactored monolithic `index.ts` (1772 lines) into 6 focused modules
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-03-10" description="v0.3.0">
|
||||
|
||||
**Bug Fixes:**
|
||||
- Updated `mem0ai` dependency with sqlite3 to better-sqlite3 migration (#4270)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-03-09" description="v0.2.0">
|
||||
|
||||
**New Features:**
|
||||
- Per-agent memory isolation for multi-agent setups via `agentId`
|
||||
- "Understanding userId" section in docs
|
||||
|
||||
**Changes:**
|
||||
- Updated config examples to use concrete `userId` values instead of placeholders
|
||||
|
||||
**Bug Fixes:**
|
||||
- Migrated platform search to Mem0 v2 API
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-02-19" description="v0.1.2">
|
||||
|
||||
**New Features:**
|
||||
- Source field for openclaw memory entries
|
||||
|
||||
**Bug Fixes:**
|
||||
- Auto-recall injection and auto-capture message drop
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-02-02" description="v0.1.0">
|
||||
|
||||
**New Features:**
|
||||
- Initial release of the OpenClaw Mem0 plugin
|
||||
- Platform mode (Mem0 Cloud) and open-source mode support
|
||||
- Auto-recall: inject relevant memories before each turn
|
||||
- Auto-capture: store facts after each turn
|
||||
- Configurable `topK`, `threshold`, and `apiVersion` options
|
||||
|
||||
</Update>
|
||||
@@ -0,0 +1,290 @@
|
||||
---
|
||||
title: "Platform"
|
||||
description: "Release notes for the Mem0 hosted platform — backend, dashboard, billing, and infrastructure changes."
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Update label="2025-07-23" description="">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Memory:** Fixed ADD functionality
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-19" description="">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** Added Settings UI and latency display
|
||||
- **Performance:** Neo4j query optimization
|
||||
|
||||
**Bug Fixes:**
|
||||
- **OpenMemory:** Fixed OMM raising unnecessary exceptions
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-18" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **UI:** Updated Event UI
|
||||
- **Performance:** Fixed N+1 query issue in semantic_search_v2 by optimizing MemorySerializer field selection
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Memory:** Fixed duplicate memory index sentry error
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-17" description="">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** New Settings Page
|
||||
- **Memory:** Duplicate memories entities support
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:** Optimized semantic search and get_all APIs by eliminating N+1 queries
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-16" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Database:** Implemented read replica routing with enhanced logging and app-specific DB routing
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:** Improved query performance in search v2 and get all v2 endpoints
|
||||
|
||||
**Bug Fixes:**
|
||||
- **API:** Fixed pagination for get all API
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-12" description="">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Graph:** Fixed social graph bugs and connection issues
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-11" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Rate Limiting:** New rate limit for V2 Search
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Slack:** Fixed Slack rate limit error with backend improvements
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-10" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:**
|
||||
- Changed connection pooling time to 5 minutes
|
||||
- Separated graph lambdas for better performance
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-09" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Graph:** Graph Optimizations V2 and memory improvements
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-08" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Database:** Added read replica support for improved database performance
|
||||
- **UI:** Implemented UI changes for Users Page
|
||||
- **Feedback:** Enabled feedback functionality
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Serializer:** Fixed GET ALL Serializer
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-05" description="">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** User Page Revamp and New Users Page
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-04" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Users:** New Users Page implementation
|
||||
- **Tools:** Added script to backfill memory categories
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Filters:** Fixed Filters Get All functionality
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-03" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Graph:** Graph Memory optimization
|
||||
- **Memory:** Fixed exact memories and semantically similar memories retrieval
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-02" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Categorization:** Refactored categorization logic to utilize Gemini 2.5 Flash and improve message handling
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-01" description="">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Memory:** Fixed old_memory issue in Async memory addition lambda
|
||||
- **Events:** Fixed missing events
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-30" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Graph:** Improvements to graph memory and added user to LTM-STM
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-28" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Graph:** Added support for SQS in graph memory addition
|
||||
- **Testing:** Added Locust load testing script and Grafana Dashboard
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-27" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Rate Limiting:** Updated rate limiting for ADD API to 1000/min
|
||||
- **Performance:** Improved Neo4j performance
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-26" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Memory:** Edit Memory From Drawer functionality
|
||||
- **API:** Added Topic Suggestions API Endpoint
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-25" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Group Chat:** Group-Chat v2 with Actor-Aware Memories
|
||||
- **Memory:** Editable Metadata in Memories
|
||||
- **UI:** Memory Actions Badges
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-19" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Rate Limiting:** Implemented comprehensive rate limiting system
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:** Added performance indexes for memory stats query
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Search:** Fixed search events not respecting top-k parameter
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-18" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Memory Management:** Implemented OpenAI Batch API for Memory Cleaning with fallback
|
||||
- **Playground:** Added Claude 4 support on Playground
|
||||
|
||||
**Improvements:**
|
||||
- **Memory:** Added ability to update memory metadata
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-17" description="">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** New Memories Page UI design
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-16" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Infrastructure:** Migrated to Application Load Balancer (ALB)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-13" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Memory Management:** Enhanced Memory Management with Cosine Similarity Fallback
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-11" description="">
|
||||
|
||||
**New Features:**
|
||||
- **OMM:** Added OMM Script and UI functionality
|
||||
|
||||
**Improvements:**
|
||||
- **API:** Added filters validation to semantic_search_v2 endpoint
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-09" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Intercom:** Set Intercom events for ADD and SEARCH operations
|
||||
- **OpenMemory:** Added Posthog integration and feedback functionality
|
||||
- **MCP:** New JavaScript MCP Server with feedback support
|
||||
|
||||
**Improvements:**
|
||||
- **Structured Data:** Enhanced structured data handling in memory management
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-06" description="">
|
||||
|
||||
**New Features:**
|
||||
- **OAuth:** Added Mem0 OAuth integration
|
||||
- **OMM:** Added OMM-Mem0 sync for deleted memories
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-05" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Filters:** Implemented Wildcard Filters and refactored filter logic in V2 Views
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-02" description="">
|
||||
|
||||
**New Features:**
|
||||
- **OpenMemory Cloud:** Added OpenMemory Cloud support
|
||||
- **Structured Data:** Added 'structured_attributes' field to Memory model
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-05-30" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Projects:** Added version and enable_graph to project views
|
||||
- **OpenMemory:** Added Postgres support for OpenMemory
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-05-19" description="">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Core:** Fixed unicode error in user_id, agent_id, run_id and app_id
|
||||
|
||||
</Update>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
---
|
||||
title: "Product Updates"
|
||||
description: "Latest releases, bug fixes, and improvements for the Mem0 Python and TypeScript SDKs."
|
||||
title: "SDK & Tools"
|
||||
description: "Release notes for the Mem0 Python SDK, TypeScript SDK, Vercel AI SDK, CLI, and editor plugins."
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Python">
|
||||
|
||||
@@ -844,7 +843,6 @@ mode: "wide"
|
||||
</Tab>
|
||||
|
||||
<Tab title="TypeScript">
|
||||
|
||||
<Update label="2026-04-04" description="v2.4.6">
|
||||
|
||||
**New Features & Updates:**
|
||||
@@ -1160,352 +1158,141 @@ mode: "wide"
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="Platform">
|
||||
<Tab title="CLI">
|
||||
|
||||
<Update label="2025-07-23" description="">
|
||||
<Update label="2026-04-06" description="Python v0.2.2 / Node v0.2.2">
|
||||
|
||||
**New Features:**
|
||||
- **Telemetry:** Added PostHog telemetry and source tracking to both Python and Node CLIs ([#4699](https://github.com/mem0ai/mem0/pull/4699))
|
||||
- **Validation:** API key validated upfront via `/v1/ping/` on startup — fail-fast with a helpful error instead of cryptic 401s ([#4701](https://github.com/mem0ai/mem0/pull/4701))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Memory:** Fixed ADD functionality
|
||||
- **CD:** Fixed OIDC trusted publishing with `npx npm@latest` ([#4724](https://github.com/mem0ai/mem0/pull/4724))
|
||||
- **CD:** Removed npm self-upgrade from CD workflows ([#4723](https://github.com/mem0ai/mem0/pull/4723))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-19" description="">
|
||||
<Update label="2026-04-03" description="Python v0.2.1 / Node v0.2.1">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** Added Settings UI and latency display
|
||||
- **Performance:** Neo4j query optimization
|
||||
- **Docs:** Comprehensive README with installation, usage examples, and purple branding ([#4680](https://github.com/mem0ai/mem0/pull/4680))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **OpenMemory:** Fixed OMM raising unnecessary exceptions
|
||||
- **npm:** Added `repository` field to Node packages for npm provenance ([#4671](https://github.com/mem0ai/mem0/pull/4671))
|
||||
- **CD:** Added CD workflows for Node SDK packages with OIDC trusted publishing ([#4670](https://github.com/mem0ai/mem0/pull/4670))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-18" description="">
|
||||
<Update label="2026-04-02" description="Python v0.2.0 / Node v0.1.1">
|
||||
|
||||
**Improvements:**
|
||||
- **UI:** Updated Event UI
|
||||
- **Performance:** Fixed N+1 query issue in semantic_search_v2 by optimizing MemorySerializer field selection
|
||||
**New Features:**
|
||||
- **`event` commands:** `mem0 event list` shows recent background processing events in a table; `mem0 event status <id>` shows full detail including nested memory results ([#4649](https://github.com/mem0ai/mem0/pull/4649))
|
||||
- **`--json` / `--agent` flag:** Root-level flag switches all command output to a structured JSON envelope for programmatic/agent consumption. Envelope format: `{"status", "command", "duration_ms", "scope", "count", "data"}` ([#4649](https://github.com/mem0ai/mem0/pull/4649))
|
||||
- **Agent output sanitization:** Raw API responses projected to only relevant fields per command (e.g., `add` → `{id, memory, event}`, `search` → `{id, memory, score, created_at, categories}`) ([#4649](https://github.com/mem0ai/mem0/pull/4649))
|
||||
- **Email login:** Added email verification code login to `mem0 init` ([#4623](https://github.com/mem0ai/mem0/pull/4623))
|
||||
- **Brand update:** Updated color palette from purple to golden ([#4664](https://github.com/mem0ai/mem0/pull/4664))
|
||||
- **CI/CD:** Added CI pipelines and CD workflows for both CLIs ([#4640](https://github.com/mem0ai/mem0/pull/4640), [#4653](https://github.com/mem0ai/mem0/pull/4653))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Memory:** Fixed duplicate memory index sentry error
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-17" description="">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** New Settings Page
|
||||
- **Memory:** Duplicate memories entities support
|
||||
- **Node:** Fixed critical `MODULE_NOT_FOUND` crash on `status`, `import`, and all commands when installed globally — replaced runtime `createRequire` with build-time version injection ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
- **Node:** API errors now show full response detail instead of bare "Bad Request" ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
- **Python:** Fixed double error printing on all commands ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
- **`status` command:** Replaced heavyweight `/v1/entities/` check with dedicated `GET /v1/ping/` endpoint ([#4649](https://github.com/mem0ai/mem0/pull/4649))
|
||||
- **`add` command:** Deduplicated PENDING results from API; changed misleading count message ([#4649](https://github.com/mem0ai/mem0/pull/4649))
|
||||
- **`init` command:** Partial flags now work in non-TTY; warns before overwriting existing config; added `--force` flag ([#4649](https://github.com/mem0ai/mem0/pull/4649))
|
||||
- **`delete` command:** Fixed entity delete via v2 API for all entity types ([#4649](https://github.com/mem0ai/mem0/pull/4649))
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:** Optimized semantic search and get_all APIs by eliminating N+1 queries
|
||||
- Tables now show full UUIDs (was truncated to 8 chars, making `mem0 get <id>` fail) ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
- Search table includes Score column ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
- `config get api_key` short-form aliases added ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
- Client-side validation for `--expires`, `--page-size`, `--page`, `--top-k`, `--threshold`, and empty content ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
- `printInfo` / `printScope` moved to stderr to avoid contaminating JSON piping ([#4636](https://github.com/mem0ai/mem0/pull/4636))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-16" description="">
|
||||
<Update label="2026-03-26" description="Python v0.1.0 / Node v0.1.0">
|
||||
|
||||
**New Features:**
|
||||
- **Database:** Implemented read replica routing with enhanced logging and app-specific DB routing
|
||||
**Initial Release — Official Mem0 CLI**
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:** Improved query performance in search v2 and get all v2 endpoints
|
||||
A full-featured command-line interface for Mem0, available in both Python and Node.js:
|
||||
|
||||
**Bug Fixes:**
|
||||
- **API:** Fixed pagination for get all API
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-12" description="">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Graph:** Fixed social graph bugs and connection issues
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-11" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Rate Limiting:** New rate limit for V2 Search
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Slack:** Fixed Slack rate limit error with backend improvements
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-10" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:**
|
||||
- Changed connection pooling time to 5 minutes
|
||||
- Separated graph lambdas for better performance
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-09" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Graph:** Graph Optimizations V2 and memory improvements
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-08" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Database:** Added read replica support for improved database performance
|
||||
- **UI:** Implemented UI changes for Users Page
|
||||
- **Feedback:** Enabled feedback functionality
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Serializer:** Fixed GET ALL Serializer
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-05" description="">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** User Page Revamp and New Users Page
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-04" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Users:** New Users Page implementation
|
||||
- **Tools:** Added script to backfill memory categories
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Filters:** Fixed Filters Get All functionality
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-03" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Graph:** Graph Memory optimization
|
||||
- **Memory:** Fixed exact memories and semantically similar memories retrieval
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-02" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Categorization:** Refactored categorization logic to utilize Gemini 2.5 Flash and improve message handling
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-07-01" description="">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Memory:** Fixed old_memory issue in Async memory addition lambda
|
||||
- **Events:** Fixed missing events
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-30" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Graph:** Improvements to graph memory and added user to LTM-STM
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-28" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Graph:** Added support for SQS in graph memory addition
|
||||
- **Testing:** Added Locust load testing script and Grafana Dashboard
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-27" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Rate Limiting:** Updated rate limiting for ADD API to 1000/min
|
||||
- **Performance:** Improved Neo4j performance
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-26" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Memory:** Edit Memory From Drawer functionality
|
||||
- **API:** Added Topic Suggestions API Endpoint
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-25" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Group Chat:** Group-Chat v2 with Actor-Aware Memories
|
||||
- **Memory:** Editable Metadata in Memories
|
||||
- **UI:** Memory Actions Badges
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-19" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Rate Limiting:** Implemented comprehensive rate limiting system
|
||||
|
||||
**Improvements:**
|
||||
- **Performance:** Added performance indexes for memory stats query
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Search:** Fixed search events not respecting top-k parameter
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-18" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Memory Management:** Implemented OpenAI Batch API for Memory Cleaning with fallback
|
||||
- **Playground:** Added Claude 4 support on Playground
|
||||
|
||||
**Improvements:**
|
||||
- **Memory:** Added ability to update memory metadata
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-17" description="">
|
||||
|
||||
**New Features:**
|
||||
- **UI:** New Memories Page UI design
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-16" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Infrastructure:** Migrated to Application Load Balancer (ALB)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-13" description="">
|
||||
|
||||
**Improvements:**
|
||||
- **Memory Management:** Enhanced Memory Management with Cosine Similarity Fallback
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-11" description="">
|
||||
|
||||
**New Features:**
|
||||
- **OMM:** Added OMM Script and UI functionality
|
||||
|
||||
**Improvements:**
|
||||
- **API:** Added filters validation to semantic_search_v2 endpoint
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-09" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Intercom:** Set Intercom events for ADD and SEARCH operations
|
||||
- **OpenMemory:** Added Posthog integration and feedback functionality
|
||||
- **MCP:** New JavaScript MCP Server with feedback support
|
||||
|
||||
**Improvements:**
|
||||
- **Structured Data:** Enhanced structured data handling in memory management
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-06" description="">
|
||||
|
||||
**New Features:**
|
||||
- **OAuth:** Added Mem0 OAuth integration
|
||||
- **OMM:** Added OMM-Mem0 sync for deleted memories
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-05" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Filters:** Implemented Wildcard Filters and refactored filter logic in V2 Views
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-02" description="">
|
||||
|
||||
**New Features:**
|
||||
- **OpenMemory Cloud:** Added OpenMemory Cloud support
|
||||
- **Structured Data:** Added 'structured_attributes' field to Memory model
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-05-30" description="">
|
||||
|
||||
**New Features:**
|
||||
- **Projects:** Added version and enable_graph to project views
|
||||
- **OpenMemory:** Added Postgres support for OpenMemory
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-05-19" description="">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Core:** Fixed unicode error in user_id, agent_id, run_id and app_id
|
||||
- **Install:** `pip install mem0-cli` (Python) or `npm install -g @mem0/cli` (Node.js)
|
||||
- **Full command suite:** `add`, `search`, `list`, `get`, `update`, `delete`, `import`, `config`, `init`, `status`, `entity`
|
||||
- **Interactive setup:** `mem0 init` with API key entry and user ID configuration
|
||||
- **Works everywhere:** Platform (Mem0 Cloud) and self-hosted OSS modes
|
||||
- **Scriptable:** `-o json` flag for CI/CD pipelines and automation
|
||||
- **Dual SDK:** Same commands, same experience across Python and Node.js
|
||||
- **Shared spec:** Both implementations driven by a single `cli-spec.json` ensuring identical behavior ([#4575](https://github.com/mem0ai/mem0/pull/4575))
|
||||
|
||||
</Update>
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="Vercel AI SDK">
|
||||
<Tab title="Plugins">
|
||||
|
||||
<Update label="2025-12-26" description="v2.0.5">
|
||||
<Update label="2026-04-02" description="mem0-plugin v1.0.0">
|
||||
|
||||
**Mem0 Plugin for Claude Code, Cursor, and Codex**
|
||||
|
||||
The unified Mem0 plugin for AI development environments:
|
||||
|
||||
- **9 MCP memory tools:** `add_memory`, `search_memories`, `get_memories`, `get_memory`, `update_memory`, `delete_memory`, `delete_all_memories`, `delete_entities`, `list_entities` — all via `mcp.mem0.ai`
|
||||
- **Lifecycle hooks:** Automatic memory capture at session start, context compaction, task completion, and session end
|
||||
- **Cloud MCP server:** Managed endpoint replaces local MCP and Smithery setup
|
||||
- **Streamable HTTP transport:** New MCP transport protocol for real-time streaming
|
||||
- **Codex-specific skill:** Dedicated skill in `mem0-plugin/skills/mem0-codex` for Codex workflows
|
||||
- **Supported editors:** Claude Code, Claude Cowork, Cursor, Codex
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2025-12-26" description="Vercel AI SDK v2.0.5">
|
||||
**Bug Fix:**
|
||||
- **Vercel AI SDK:** Removed unnecessary dependencies to make the package lighter.
|
||||
- Removed unnecessary dependencies to make the package lighter.
|
||||
</Update>
|
||||
|
||||
<Update label="2025-09-25" description="v2.0.4">
|
||||
<Update label="2025-09-25" description="Vercel AI SDK v2.0.3 – v2.0.4">
|
||||
**New Features:**
|
||||
- Added file support for multimodal capabilities with memory context (v2.0.3)
|
||||
|
||||
**Bug Fix:**
|
||||
- **Vercel AI SDK:** Fixed version parameter in the AI SDK to use V2 for addition.
|
||||
- Fixed version parameter to use V2 for addition (v2.0.4)
|
||||
</Update>
|
||||
|
||||
<Update label="2025-09-25" description="v2.0.3">
|
||||
**New Features:**
|
||||
- **Vercel AI SDK:** Added file support for multimodal capabilities with memory context
|
||||
</Update>
|
||||
|
||||
<Update label="2025-09-03" description="v2.0.2">
|
||||
<Update label="2025-09-03" description="Vercel AI SDK v2.0.2">
|
||||
**Bug Fix:**
|
||||
- **Vercel AI SDK:** Fixed streaming response in the AI SDK.
|
||||
- Fixed streaming response in the AI SDK.
|
||||
</Update>
|
||||
|
||||
<Update label="2025-08-05" description="v2.0.1">
|
||||
<Update label="2025-08-05" description="Vercel AI SDK v2.0.0 – v2.0.1">
|
||||
**New Features:**
|
||||
- **Vercel AI SDK:** Added a new param `host` to the config.
|
||||
- Migration to AI SDK V5 (v2.0.0)
|
||||
- Added `host` param to the config (v2.0.1)
|
||||
</Update>
|
||||
|
||||
<Update label="2025-08-05" description="v2.0.0">
|
||||
<Update label="2025-06-15" description="Vercel AI SDK v1.0.6">
|
||||
**New Features:**
|
||||
- **Vercel AI SDK:** Migration to AI SDK V5.
|
||||
- Added `filter_memories` param.
|
||||
</Update>
|
||||
|
||||
<Update label="2025-06-15" description="v1.0.6">
|
||||
<Update label="2025-05-23" description="Vercel AI SDK v1.0.5">
|
||||
**New Features:**
|
||||
- **Vercel AI SDK:** Added param `filter_memories`.
|
||||
- Added support for Google provider.
|
||||
</Update>
|
||||
|
||||
<Update label="2025-05-23" description="v1.0.5">
|
||||
<Update label="2025-05-10" description="Vercel AI SDK v1.0.3 – v1.0.4">
|
||||
**New Features:**
|
||||
- **Vercel AI SDK:** Added support for Google provider.
|
||||
</Update>
|
||||
- Added support for `output_format` param (v1.0.4)
|
||||
|
||||
<Update label="2025-05-10" description="v1.0.4">
|
||||
**New Features:**
|
||||
- **Vercel AI SDK:** Added support for new param `output_format`.
|
||||
</Update>
|
||||
|
||||
<Update label="2025-05-08" description="v1.0.3">
|
||||
**Improvements:**
|
||||
- **Vercel AI SDK:** Added support for graceful failure in cases services are down.
|
||||
- Added graceful failure handling when services are down (v1.0.3)
|
||||
</Update>
|
||||
|
||||
<Update label="2025-05-01" description="v1.0.1">
|
||||
<Update label="2025-05-01" description="Vercel AI SDK v1.0.1">
|
||||
**New Features:**
|
||||
- **Vercel AI SDK:** Added support for graph memories
|
||||
- Added support for graph memories.
|
||||
</Update>
|
||||
|
||||
</Tab>
|
||||
|
||||
</Tabs>
|
||||
|
||||
@@ -45,7 +45,7 @@ Before you begin, follow these steps to set up the demo application:
|
||||
OPENAI_API_KEY=your_openai_api_key
|
||||
MEM0_API_KEY=your_mem0_api_key
|
||||
```
|
||||
You can obtain your `MEM0_API_KEY` by signing up at [Mem0 API Dashboard](https://app.mem0.ai/dashboard/api-keys).
|
||||
You can obtain your `MEM0_API_KEY` by signing up at <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Dashboard</a>.
|
||||
|
||||
5. Start the development server:
|
||||
```bash
|
||||
|
||||
@@ -38,7 +38,7 @@ client = MemoryClient(api_key="your-api-key")
|
||||
```
|
||||
|
||||
<Note>
|
||||
Replace `your-api-key` with your actual Mem0 API key from the [dashboard](https://app.mem0.ai). Without proper API authentication, memory operations will fail.
|
||||
Replace `your-api-key` with your actual Mem0 API key from the <a href="https://app.mem0.ai" rel="nofollow">dashboard</a>. Without proper API authentication, memory operations will fail.
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
@@ -17,7 +17,7 @@ from mem0 import MemoryClient
|
||||
client = MemoryClient(api_key="m0-...")
|
||||
```
|
||||
|
||||
Grab an API key from the <Link href="https://app.mem0.ai/">Mem0 dashboard</Link> to get started.
|
||||
Grab an API key from the <a href="https://app.mem0.ai/" rel="nofollow">Mem0 dashboard</a> to get started.
|
||||
|
||||
## Store and Retrieve Scoped Memories
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ client = MemoryClient(api_key="your-api-key")
|
||||
```
|
||||
|
||||
<Note>
|
||||
Your API key needs export permissions to download memory data. Check your project settings on the [dashboard](https://app.mem0.ai) if export operations fail with authentication errors.
|
||||
Your API key needs export permissions to download memory data. Check your project settings on the <a href="https://app.mem0.ai" rel="nofollow">dashboard</a> if export operations fail with authentication errors.
|
||||
</Note>
|
||||
|
||||
Let's add some sample memories to work with:
|
||||
|
||||
@@ -55,7 +55,7 @@ GEMINI_API_KEY=your-gemini-api-key-here
|
||||
```
|
||||
|
||||
<Note>
|
||||
Ensure you have your Mem0 API key from the [Mem0 Dashboard](https://app.mem0.ai) and your Gemini API key from the [Google AI Studio](https://ai.studio/app/api-keys).
|
||||
Ensure you have your Mem0 API key from the <a href="https://app.mem0.ai" rel="nofollow">Mem0 Dashboard</a> and your Gemini API key from the [Google AI Studio](https://ai.studio/app/api-keys).
|
||||
</Note>
|
||||
|
||||
## Gemini Memory Agent
|
||||
|
||||
@@ -41,7 +41,7 @@ Set up your environment variables:
|
||||
- `MEM0_API_KEY`: Your Mem0 Platform API key
|
||||
- `OPENAI_API_KEY`: Your OpenAI API key
|
||||
|
||||
You can obtain your Mem0 Platform API key from the [Mem0 Platform](https://app.mem0.ai).
|
||||
You can obtain your Mem0 Platform API key from the <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.
|
||||
|
||||
## Complete Implementation
|
||||
|
||||
@@ -357,7 +357,7 @@ Based on our previous session, I remember we covered Vision Language Models and
|
||||
## Help & Resources
|
||||
|
||||
- [LlamaIndex Agent Workflows](https://docs.llamaindex.ai/en/stable/use_cases/agents/)
|
||||
- [Mem0 Platform](https://app.mem0.ai/)
|
||||
- <a href="https://app.mem0.ai/" rel="nofollow">Mem0 Platform</a>
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ os.environ["OPENAI_API_KEY"] = "<your-openai-api-key>"
|
||||
llm = OpenAI(model="gpt-4.1-nano-2025-04-14")
|
||||
```
|
||||
|
||||
Initialize the Mem0 client. You can find your API key [here](https://app.mem0.ai/dashboard/api-keys). Read about Mem0 [Open Source](https://docs.mem0.ai/open-source/overview).
|
||||
Initialize the Mem0 client. You can find your API key <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">here</a>. Read about Mem0 [Open Source](https://docs.mem0.ai/open-source/overview).
|
||||
```python
|
||||
os.environ["MEM0_API_KEY"] = "<your-mem0-api-key>"
|
||||
|
||||
|
||||
@@ -754,7 +754,7 @@ Exact output varies as Mem0 automatically extracts and deduplicates entities. Th
|
||||
- [MiroFish GitHub](https://github.com/666ghj/MiroFish) — Source code and setup guide
|
||||
- [MiroFish Documentation](https://deepwiki.com/666ghj/MiroFish) — Full framework docs
|
||||
- [Mem0 Graph Memory](/open-source/features/graph-memory) — Graph Memory documentation
|
||||
- [Mem0 Documentation](https://docs.mem0.ai/) — Full API reference
|
||||
- [Mem0 Documentation](https://docs.mem0.ai/introduction) — Full API reference
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Graph Memory" icon="network-wired" href="/open-source/features/graph-memory">
|
||||
|
||||
@@ -222,8 +222,8 @@ context = Mem0Context(user_id="user123")
|
||||
|
||||
## Resources
|
||||
|
||||
- [Mem0 Documentation](https://docs.mem0.ai)
|
||||
- [Mem0 Dashboard](https://app.mem0.ai/dashboard)
|
||||
- [Mem0 Documentation](https://docs.mem0.ai/introduction)
|
||||
- <a href="https://app.mem0.ai/dashboard" rel="nofollow">Mem0 Dashboard</a>
|
||||
- [API Reference](https://docs.mem0.ai/api-reference)
|
||||
|
||||
---
|
||||
|
||||
@@ -23,7 +23,7 @@ MEM0_API_KEY=your_mem0_api_key
|
||||
OPENAI_API_KEY=your_openai_api_key
|
||||
```
|
||||
|
||||
Get your Mem0 API key from the [Mem0 Dashboard](https://app.mem0.ai/dashboard/api-keys).
|
||||
Get your Mem0 API key from the <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 Dashboard</a>.
|
||||
|
||||
### Configuration
|
||||
|
||||
@@ -308,8 +308,8 @@ run().catch(console.error);
|
||||
|
||||
## Resources
|
||||
|
||||
- [Mem0 Documentation](https://docs.mem0.ai)
|
||||
- [Mem0 Dashboard](https://app.mem0.ai/dashboard)
|
||||
- [Mem0 Documentation](https://docs.mem0.ai/introduction)
|
||||
- <a href="https://app.mem0.ai/dashboard" rel="nofollow">Mem0 Dashboard</a>
|
||||
- [API Reference](https://docs.mem0.ai/api-reference)
|
||||
- [OpenAI Documentation](https://platform.openai.com/docs)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Adding memory is how Mem0 captures useful details from a conversation so your ag
|
||||
- **Messages** – The ordered list of user/assistant turns you send to `add`.
|
||||
- **Infer** – Controls whether Mem0 extracts structured memories (`infer=True`, default) or stores raw messages.
|
||||
- **Metadata** – Optional filters (e.g., `{"category": "movie_recommendations"}`) that improve retrieval later.
|
||||
- **User / Session identifiers** – `user_id`, `session_id`, or `run_id` that scope the memory for future searches.
|
||||
- **User / Session identifiers** – `user_id`, `agent_id`, or `run_id` that scope the memory for future searches.
|
||||
|
||||
## How does it work?
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ Mem0 maps these classic categories onto its layered storage so you can decide wh
|
||||
Mem0 stores each layer separately and merges them when you query:
|
||||
|
||||
1. **Capture** – Messages enter the conversation layer while the turn is active.
|
||||
2. **Promote** – Relevant details persist to session or user memory based on your `user_id`, `session_id`, and metadata.
|
||||
2. **Promote** – Relevant details persist to session or user memory based on your `user_id`, `run_id`, and metadata.
|
||||
3. **Retrieve** – The search pipeline pulls from all layers, ranking user memories first, then session notes, then raw history.
|
||||
|
||||
```python
|
||||
@@ -66,19 +66,19 @@ memory = Memory(api_key=os.environ["MEM0_API_KEY"])
|
||||
memory.add(
|
||||
["I'm Alex and I prefer boutique hotels."],
|
||||
user_id="alex",
|
||||
session_id="trip-planning-2025",
|
||||
run_id="trip-planning-2025",
|
||||
)
|
||||
|
||||
# Later in the session, pull long-term + session context
|
||||
results = memory.search(
|
||||
"Any hotel preferences?",
|
||||
user_id="alex",
|
||||
session_id="trip-planning-2025",
|
||||
run_id="trip-planning-2025",
|
||||
)
|
||||
```
|
||||
|
||||
<Tip>
|
||||
Use `session_id` when you want short-term context to expire automatically; rely on `user_id` for lasting personalization.
|
||||
Use `run_id` when you want short-term context to expire automatically; rely on `user_id` for lasting personalization.
|
||||
</Tip>
|
||||
|
||||
## When should you use each layer?
|
||||
|
||||
+9
-2
@@ -12,7 +12,7 @@
|
||||
"logo": {
|
||||
"light": "/logo/light.svg",
|
||||
"dark": "/logo/dark.svg",
|
||||
"href": "https://app.mem0.ai/"
|
||||
"href": "https://mem0.ai"
|
||||
},
|
||||
"navigation": {
|
||||
"anchors": [
|
||||
@@ -138,7 +138,10 @@
|
||||
"group": "Release Notes",
|
||||
"icon": "rocket",
|
||||
"pages": [
|
||||
"changelog"
|
||||
"changelog/highlights",
|
||||
"changelog/sdk",
|
||||
"changelog/platform",
|
||||
"changelog/openclaw"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -609,6 +612,10 @@
|
||||
]
|
||||
},
|
||||
"redirects": [
|
||||
{
|
||||
"source": "/changelog",
|
||||
"destination": "/changelog/highlights"
|
||||
},
|
||||
{
|
||||
"source": "/api-reference/memory/v2-search-memories",
|
||||
"destination": "/api-reference/memory/search-memories"
|
||||
|
||||
@@ -24,7 +24,7 @@ pip install mem0ai agentops python-dotenv
|
||||
2. Valid API keys:
|
||||
- [AgentOps API Key](https://app.agentops.ai/dashboard/api-keys)
|
||||
- OpenAI API Key (for LLM operations)
|
||||
- [Mem0 API Key](https://app.mem0.ai/dashboard/api-keys) (optional, for cloud operations)
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key</a> (optional, for cloud operations)
|
||||
|
||||
## Basic Integration Example
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ pip install agno mem0ai python-dotenv
|
||||
```
|
||||
|
||||
2. Valid API keys:
|
||||
- [Mem0 API Key](https://app.mem0.ai/dashboard/api-keys)
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key</a>
|
||||
- OpenAI API Key (for the agent model)
|
||||
|
||||
## Quick Integration (Using `Mem0Tools`)
|
||||
|
||||
@@ -19,7 +19,7 @@ pip install autogen mem0ai openai python-dotenv
|
||||
|
||||
First, we'll import the necessary libraries and set up our configurations.
|
||||
|
||||
<Note>Remember to get the Mem0 API key from [Mem0 Platform](https://app.mem0.ai).</Note>
|
||||
<Note>Remember to get the Mem0 API key from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.</Note>
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
@@ -18,7 +18,7 @@ In this guide, you'll:
|
||||
- **Python 3.12+**
|
||||
- **[uv](https://docs.astral.sh/uv/)** — Python package manager
|
||||
- **Node.js 18+** and **npm** — only needed if using the web console
|
||||
- A **Mem0 API key** from [app.mem0.ai](https://app.mem0.ai)
|
||||
- A **Mem0 API key** from <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a>
|
||||
- An **OpenAI API key** (or another LLM provider supported by ChatDev)
|
||||
|
||||
## Setup and Configuration
|
||||
@@ -39,7 +39,7 @@ cd frontend && npm install && cd ..
|
||||
|
||||
Set up your environment variables in a `.env` file:
|
||||
|
||||
<Note>Get your Mem0 API key from [Mem0 Platform](https://app.mem0.ai).</Note>
|
||||
<Note>Get your Mem0 API key from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.</Note>
|
||||
|
||||
```bash
|
||||
MEM0_API_KEY=your-mem0-api-key
|
||||
@@ -194,7 +194,7 @@ This means retrieval returns memories from **both** the user's scope and the age
|
||||
|
||||
| Field | Required | Description |
|
||||
|-------|----------|-------------|
|
||||
| `api_key` | Yes | Mem0 API key from [app.mem0.ai](https://app.mem0.ai) |
|
||||
| `api_key` | Yes | Mem0 API key from <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a> |
|
||||
| `user_id` | No | Scope memories to a specific user |
|
||||
| `agent_id` | No | Scope memories to a specific agent |
|
||||
|
||||
@@ -216,9 +216,9 @@ This means retrieval returns memories from **both** the user's scope and the age
|
||||
|
||||
- **No memories returned on first run** — This is expected. Memories are stored *after* the agent responds, so the first interaction has no prior context. Memories appear starting from the second interaction onward.
|
||||
- **`mem0ai` not installed** — If you see `ImportError: mem0ai is required for Mem0Memory`, run `uv add mem0ai` or `pip install mem0ai` to add the dependency.
|
||||
- **Invalid API key** — A wrong or expired `MEM0_API_KEY` will log errors like `Mem0 search failed` or `Mem0 add failed` but won't crash the agent. Check your key at [app.mem0.ai](https://app.mem0.ai).
|
||||
- **Invalid API key** — A wrong or expired `MEM0_API_KEY` will log errors like `Mem0 search failed` or `Mem0 add failed` but won't crash the agent. Check your key at <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a>.
|
||||
- **Pipeline headers in memories** — ChatDev automatically strips internal pipeline headers (e.g., `=== INPUT FROM TASK (user) ===`) before sending text to Mem0, so your memories stay clean.
|
||||
- **Clearing test memories** — To delete memories created during testing, use the Mem0 dashboard at [app.mem0.ai](https://app.mem0.ai) or the Python SDK: `MemoryClient().delete_all(user_id="your-test-user")`.
|
||||
- **Clearing test memories** — To delete memories created during testing, use the Mem0 dashboard at <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a> or the Python SDK: `MemoryClient().delete_all(user_id="your-test-user")`.
|
||||
|
||||
## Key Features
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ Add persistent memory to [**Claude Code**](https://docs.anthropic.com/en/docs/cl
|
||||
Before setting up Mem0 with Claude Code, ensure you have:
|
||||
|
||||
1. A Mem0 Platform account and API key:
|
||||
- [Sign up at app.mem0.ai](https://app.mem0.ai)
|
||||
- [Get your API key](https://app.mem0.ai/dashboard/api-keys) (starts with `m0-`)
|
||||
- <a href="https://app.mem0.ai" rel="nofollow">Sign up at app.mem0.ai</a>
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Get your API key</a> (starts with `m0-`)
|
||||
|
||||
2. Claude Code CLI or Claude Cowork desktop app installed
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ Add persistent memory to [**OpenAI Codex**](https://openai.com/index/codex/) wit
|
||||
Before setting up Mem0 with Codex, ensure you have:
|
||||
|
||||
1. A Mem0 Platform account and API key:
|
||||
- [Sign up at app.mem0.ai](https://app.mem0.ai)
|
||||
- [Get your API key](https://app.mem0.ai/dashboard/api-keys) (starts with `m0-`)
|
||||
- <a href="https://app.mem0.ai" rel="nofollow">Sign up at app.mem0.ai</a>
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Get your API key</a> (starts with `m0-`)
|
||||
|
||||
2. OpenAI Codex access
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ pip install crewai crewai-tools mem0ai
|
||||
|
||||
Import required modules and set up configurations:
|
||||
|
||||
<Note>Remember to get your API keys from [Mem0 Platform](https://app.mem0.ai), [OpenAI](https://platform.openai.com) and [Serper Dev](https://serper.dev) for search capabilities.</Note>
|
||||
<Note>Remember to get your API keys from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>, [OpenAI](https://platform.openai.com) and [Serper Dev](https://serper.dev) for search capabilities.</Note>
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
@@ -17,8 +17,8 @@ Add persistent memory to [**Cursor**](https://cursor.com) with the Mem0 plugin.
|
||||
Before setting up Mem0 with Cursor, ensure you have:
|
||||
|
||||
1. A Mem0 Platform account and API key:
|
||||
- [Sign up at app.mem0.ai](https://app.mem0.ai)
|
||||
- [Get your API key](https://app.mem0.ai/dashboard/api-keys) (starts with `m0-`)
|
||||
- <a href="https://app.mem0.ai" rel="nofollow">Sign up at app.mem0.ai</a>
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Get your API key</a> (starts with `m0-`)
|
||||
|
||||
2. Cursor installed ([cursor.com](https://cursor.com))
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ npx flowise start
|
||||
|
||||
### 2. Obtain Your Mem0 API Key
|
||||
|
||||
1. Navigate to the [Mem0 API Key dashboard](https://app.mem0.ai/dashboard/api-keys).
|
||||
1. Navigate to the <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key dashboard</a>.
|
||||
2. Generate or copy your existing Mem0 API Key.
|
||||
|
||||

|
||||
@@ -70,7 +70,7 @@ Test your memory configuration:
|
||||
|
||||
1. Save your Flowise configuration
|
||||
2. Run a test chat and store some information
|
||||
3. Verify the stored memories in the [Mem0 Dashboard](https://app.mem0.ai/dashboard/requests)
|
||||
3. Verify the stored memories in the <a href="https://app.mem0.ai/dashboard/requests" rel="nofollow">Mem0 Dashboard</a>
|
||||
|
||||

|
||||
|
||||
@@ -103,7 +103,7 @@ Available settings include:
|
||||
|
||||
### Platform Configuration
|
||||
|
||||
Additional settings available in [Mem0 Project Settings](https://app.mem0.ai/dashboard/project-settings):
|
||||
Additional settings available in <a href="https://app.mem0.ai/dashboard/project-settings" rel="nofollow">Mem0 Project Settings</a>:
|
||||
|
||||
1. **Custom Instructions**: Define memory extraction rules
|
||||
2. **Expiration Date**: Set automatic memory cleanup periods
|
||||
|
||||
@@ -22,7 +22,7 @@ pip install google-adk mem0ai python-dotenv
|
||||
```
|
||||
|
||||
2. Valid API keys:
|
||||
- [Mem0 API Key](https://app.mem0.ai/dashboard/api-keys)
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key</a>
|
||||
- Google AI Studio API Key
|
||||
|
||||
## Basic Integration Example
|
||||
|
||||
@@ -52,7 +52,7 @@ hermes memory setup
|
||||
|
||||
Select **mem0** as the provider and enter your Mem0 API key when prompted. The wizard writes your config to `~/.hermes/mem0.json`.
|
||||
|
||||
<Note>Get your API key from [app.mem0.ai](https://app.mem0.ai).</Note>
|
||||
<Note>Get your API key from <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a>.</Note>
|
||||
|
||||
### Option 2: Manual Configuration
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ Combining Mem0 with Keywords AI allows you to:
|
||||
4. Optimize token usage and reduce costs
|
||||
|
||||
<Note>
|
||||
You can get your Mem0 API key, user_id, and org_id from the [Mem0 dashboard](https://app.mem0.ai/). These are required for proper integration.
|
||||
You can get your Mem0 API key, user_id, and org_id from the <a href="https://app.mem0.ai/" rel="nofollow">Mem0 dashboard</a>. These are required for proper integration.
|
||||
</Note>
|
||||
|
||||
## Setup and Configuration
|
||||
|
||||
@@ -22,7 +22,7 @@ pip install langchain langchain_openai mem0ai python-dotenv
|
||||
|
||||
Import required modules and set up configurations:
|
||||
|
||||
<Note>Remember to get the Mem0 API key from [Mem0 Platform](https://app.mem0.ai).</Note>
|
||||
<Note>Remember to get the Mem0 API key from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.</Note>
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
@@ -23,7 +23,7 @@ pip install langgraph langchain-openai mem0ai python-dotenv
|
||||
|
||||
Import required modules and set up configurations:
|
||||
|
||||
<Note>Remember to get the Mem0 API key from [Mem0 Platform](https://app.mem0.ai).</Note>
|
||||
<Note>Remember to get the Mem0 API key from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.</Note>
|
||||
|
||||
```python
|
||||
from typing import Annotated, TypedDict, List
|
||||
|
||||
@@ -22,7 +22,7 @@ pip install llama-index-core llama-index-memory-mem0 python-dotenv
|
||||
Set your Mem0 Platform API key as an environment variable. You can replace `<your-mem0-api-key>` with your actual API key:
|
||||
|
||||
<Note type="info">
|
||||
You can obtain your Mem0 Platform API key from the [Mem0 Platform](https://app.mem0.ai/login).
|
||||
You can obtain your Mem0 Platform API key from the <a href="https://app.mem0.ai/login" rel="nofollow">Mem0 Platform</a>.
|
||||
</Note>
|
||||
|
||||
```python
|
||||
|
||||
@@ -23,7 +23,7 @@ npm install @mastra/core @mastra/mem0 @ai-sdk/openai zod
|
||||
|
||||
Set up your environment variables:
|
||||
|
||||
<Note>Remember to get the Mem0 API key from [Mem0 Platform](https://app.mem0.ai).</Note>
|
||||
<Note>Remember to get the Mem0 API key from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.</Note>
|
||||
|
||||
```bash
|
||||
MEM0_API_KEY=your-mem0-api-key
|
||||
|
||||
@@ -22,7 +22,7 @@ pip install openai-agents mem0ai
|
||||
```
|
||||
|
||||
2. Valid API keys:
|
||||
- [Mem0 API Key](https://app.mem0.ai/dashboard/api-keys)
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key</a>
|
||||
- [OpenAI API Key](https://platform.openai.com/api-keys)
|
||||
|
||||
## Basic Integration Example
|
||||
|
||||
@@ -42,7 +42,7 @@ All memories are scoped to this `userId` — different values create separate me
|
||||
|
||||
### Platform Mode (Mem0 Cloud)
|
||||
|
||||
<Note>Get your API key from [app.mem0.ai](https://app.mem0.ai).</Note>
|
||||
<Note>Get your API key from <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a>.</Note>
|
||||
|
||||
Add to your `openclaw.json`:
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ Mem0 is a self-improving memory layer for LLM applications, enabling personalize
|
||||
|
||||
**Get your API Key**: You'll need a Mem0 API key to use this extension:
|
||||
|
||||
a. Sign up at [app.mem0.ai](https://app.mem0.ai)
|
||||
a. Sign up at <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a>
|
||||
|
||||
b. Navigate to your API Keys page
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ npm install @mem0/vercel-ai-provider
|
||||
|
||||
### Setting Up Mem0
|
||||
|
||||
1. Get your **Mem0 API Key** from the [Mem0 Dashboard](https://app.mem0.ai/dashboard/api-keys).
|
||||
1. Get your **Mem0 API Key** from the <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 Dashboard</a>.
|
||||
|
||||
2. Initialize the Mem0 Client in your application:
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Move your Mem0 implementation to managed infrastructure with enterprise features
|
||||
|
||||
## Plan
|
||||
|
||||
1. **Sign up**: Create an account on [Mem0 Platform](https://app.mem0.ai).
|
||||
1. **Sign up**: Create an account on <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.
|
||||
2. **Get API Key**: Navigate to **Settings > API Keys** and generate a new key.
|
||||
3. **Review Usage**: Identify where you instantiate `Memory` and where you call `search` or `get_all`.
|
||||
|
||||
@@ -368,7 +368,7 @@ If you encounter issues, you can revert immediately by switching your import bac
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Platform Dashboard](https://app.mem0.ai) - Monitor usage and manage settings.
|
||||
- <a href="https://app.mem0.ai" rel="nofollow">Platform Dashboard</a> - Monitor usage and manage settings.
|
||||
- [Webhooks Setup](/platform/features/webhooks) - Configure real-time event notifications.
|
||||
- [Organizations & Projects](/api-reference/organizations-projects) - Set up multi-tenancy for your team.
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ estimatedTime: "~2 minutes"
|
||||
|
||||
<Info>
|
||||
**Prerequisites**
|
||||
- Mem0 Platform account ([Sign up here](https://app.mem0.ai))
|
||||
- API key ([Get one from dashboard](https://app.mem0.ai/settings/api-keys))
|
||||
- Mem0 Platform account (<a href="https://app.mem0.ai" rel="nofollow">Sign up here</a>)
|
||||
- API key (<a href="https://app.mem0.ai/settings/api-keys" rel="nofollow">Get one from dashboard</a>)
|
||||
- Node.js 14+ (for npx)
|
||||
- An MCP-compatible client (Claude, Claude Code, Cursor, Windsurf, VS Code, OpenCode)
|
||||
</Info>
|
||||
@@ -163,7 +163,7 @@ Agent: Updated your project status successfully.
|
||||
```
|
||||
|
||||
<Info icon="check">
|
||||
If you get "Connection failed", ensure you have a valid API key from [Mem0 Dashboard](https://app.mem0.ai/settings/api-keys).
|
||||
If you get "Connection failed", ensure you have a valid API key from <a href="https://app.mem0.ai/settings/api-keys" rel="nofollow">Mem0 Dashboard</a>.
|
||||
</Info>
|
||||
|
||||
---
|
||||
@@ -171,7 +171,7 @@ Agent: Updated your project status successfully.
|
||||
## Quick Recovery
|
||||
|
||||
- **"Connection refused"** → Check your internet connection and ensure the MCP client is correctly configured
|
||||
- **"Invalid API key"** → Get a new key from [Mem0 Dashboard](https://app.mem0.ai/settings/api-keys)
|
||||
- **"Invalid API key"** → Get a new key from <a href="https://app.mem0.ai/settings/api-keys" rel="nofollow">Mem0 Dashboard</a>
|
||||
- **"npx command not found"** → Install Node.js from [nodejs.org](https://nodejs.org)
|
||||
|
||||
---
|
||||
|
||||
@@ -64,7 +64,7 @@ Mem0 is the memory engine that keeps conversations contextual so users never rep
|
||||
<Card title="Connect Integrations" icon="plug" href="/integrations">
|
||||
LangChain, CrewAI, Vercel AI SDK.
|
||||
</Card>
|
||||
<Card title="Monitor in the Dashboard" icon="presentation" href="https://app.mem0.ai">
|
||||
<Card title="Monitor in the Dashboard" icon="presentation" href="https://app.mem0.ai/login">
|
||||
Track activity and manage workspaces.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -150,7 +150,7 @@ Mem0 offers two powerful ways to add memory to your AI applications. Choose base
|
||||
<Card
|
||||
title="Try Platform Free"
|
||||
icon="rocket"
|
||||
href="https://app.mem0.ai"
|
||||
href="https://app.mem0.ai/login"
|
||||
>
|
||||
Sign up and test the Platform with our free tier. No credit card required.
|
||||
</Card>
|
||||
|
||||
@@ -9,8 +9,8 @@ Get started with Mem0 Platform's hosted API in under 5 minutes. This guide shows
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Mem0 Platform account ([Sign up here](https://app.mem0.ai))
|
||||
- API key ([Get one from dashboard](https://app.mem0.ai/dashboard/settings?tab=api-keys&subtab=configuration))
|
||||
- Mem0 Platform account (<a href="https://app.mem0.ai" rel="nofollow">Sign up here</a>)
|
||||
- API key (<a href="https://app.mem0.ai/dashboard/settings?tab=api-keys&subtab=configuration" rel="nofollow">Get one from dashboard</a>)
|
||||
- Python 3.10+, Node.js 14+, or cURL
|
||||
|
||||
## Installation
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ We follow the llms.txt standard:
|
||||
- [llms.txt](https://docs.mem0.ai/llms.txt)
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Get an API Key" icon="key" href="https://app.mem0.ai">
|
||||
<Card title="Get an API Key" icon="key" href="https://app.mem0.ai/login">
|
||||
Sign up for Mem0 Platform and start building
|
||||
</Card>
|
||||
<Card title="Quickstart" icon="rocket" href="/platform/quickstart">
|
||||
@@ -34,7 +34,7 @@ Works with Claude Code, Cursor, Windsurf, and any assistant that supports skills
|
||||
|
||||
Connect Claude, Claude Code, Cursor, Windsurf, VS Code, OpenCode, or any MCP-compatible client to Mem0.
|
||||
|
||||
Get your API key from [app.mem0.ai](https://app.mem0.ai), then add Mem0 MCP with a single command:
|
||||
Get your API key from <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a>, then add Mem0 MCP with a single command:
|
||||
|
||||
```bash
|
||||
npx mcp-add \
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { OpenAILLM } from "./openai";
|
||||
import { LLMConfig, Message } from "../types";
|
||||
import { LLMResponse } from "./base";
|
||||
|
||||
export class DeepSeekLLM extends OpenAILLM {
|
||||
constructor(config: LLMConfig) {
|
||||
const apiKey = config.apiKey || process.env.DEEPSEEK_API_KEY;
|
||||
if (!apiKey) {
|
||||
throw new Error("DeepSeek API key is required");
|
||||
}
|
||||
super({
|
||||
...config,
|
||||
apiKey,
|
||||
baseURL:
|
||||
config.baseURL ||
|
||||
process.env.DEEPSEEK_API_BASE ||
|
||||
"https://api.deepseek.com",
|
||||
model: config.model || "deepseek-chat",
|
||||
});
|
||||
}
|
||||
|
||||
async generateResponse(
|
||||
messages: Message[],
|
||||
responseFormat?: { type: string },
|
||||
tools?: any[],
|
||||
): Promise<string | LLMResponse> {
|
||||
try {
|
||||
return await super.generateResponse(messages, responseFormat, tools);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
throw new Error(`DeepSeek LLM failed: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async generateChat(messages: Message[]): Promise<LLMResponse> {
|
||||
try {
|
||||
return await super.generateChat(messages);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
throw new Error(`DeepSeek LLM failed: ${message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import { LangchainEmbedder } from "../embeddings/langchain";
|
||||
import { LangchainVectorStore } from "../vector_stores/langchain";
|
||||
import { AzureAISearch } from "../vector_stores/azure_ai_search";
|
||||
import { PGVector } from "../vector_stores/pgvector";
|
||||
import { DeepSeekLLM } from "../llms/deepseek";
|
||||
|
||||
export class EmbedderFactory {
|
||||
static create(provider: string, config: EmbeddingConfig): Embedder {
|
||||
@@ -82,6 +83,8 @@ export class LLMFactory {
|
||||
return new MistralLLM(config);
|
||||
case "langchain":
|
||||
return new LangchainLLM(config);
|
||||
case "deepseek":
|
||||
return new DeepSeekLLM(config);
|
||||
default:
|
||||
throw new Error(`Unsupported LLM provider: ${provider}`);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,25 @@ try {
|
||||
const POSTHOG_API_KEY = "phc_hgJkUVJFYtmaJqrvf6CYN67TIQ8yhXAkWzUn9AMU4yX";
|
||||
const POSTHOG_HOST = "https://us.i.posthog.com/i/v0/e/";
|
||||
|
||||
// Default sampling rate for hot-path OSS events. Lifecycle events always fire at 100%.
|
||||
// Override via MEM0_TELEMETRY_SAMPLE_RATE env var. Mirrors mem0/memory/telemetry.py.
|
||||
const DEFAULT_SAMPLE_RATE = 0.1;
|
||||
const MEM0_TELEMETRY_SAMPLE_RATE: number = ((): number => {
|
||||
try {
|
||||
const raw = process?.env?.MEM0_TELEMETRY_SAMPLE_RATE;
|
||||
if (raw !== undefined) {
|
||||
const parsed = Number(raw);
|
||||
if (Number.isFinite(parsed) && parsed >= 0 && parsed <= 1) {
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
return DEFAULT_SAMPLE_RATE;
|
||||
})();
|
||||
|
||||
// Events that bypass sampling. Keep in sync with _captureEvent call sites in memory/index.ts.
|
||||
const LIFECYCLE_EVENTS: ReadonlySet<string> = new Set(["init", "reset"]);
|
||||
|
||||
class UnifiedTelemetry implements TelemetryClient {
|
||||
private apiKey: string;
|
||||
private host: string;
|
||||
@@ -78,6 +97,12 @@ async function captureClientEvent(
|
||||
return;
|
||||
}
|
||||
|
||||
// >= so that rate=0 drops everything and rate=1 keeps everything (Math.random() ∈ [0, 1)).
|
||||
const isLifecycle = LIFECYCLE_EVENTS.has(eventName);
|
||||
if (!isLifecycle && Math.random() >= MEM0_TELEMETRY_SAMPLE_RATE) {
|
||||
return;
|
||||
}
|
||||
|
||||
const eventData: TelemetryEventData = {
|
||||
function: `${instance.constructor.name}`,
|
||||
method: eventName,
|
||||
@@ -86,6 +111,8 @@ async function captureClientEvent(
|
||||
client_version: version,
|
||||
client_source: "nodejs",
|
||||
...additionalData,
|
||||
// sample_rate set AFTER the spread so callers can never override it
|
||||
sample_rate: isLifecycle ? 1.0 : MEM0_TELEMETRY_SAMPLE_RATE,
|
||||
};
|
||||
|
||||
await telemetry.captureEvent(
|
||||
|
||||
@@ -23,6 +23,8 @@ export interface TelemetryEventData {
|
||||
timestamp?: string;
|
||||
client_source: "browser" | "nodejs";
|
||||
client_version: string;
|
||||
/** Set by the sampling layer so PostHog dashboards can extrapolate via 1/sample_rate. */
|
||||
sample_rate?: number;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/// <reference types="jest" />
|
||||
/**
|
||||
* DeepSeek LLM — unit tests (mocked OpenAI).
|
||||
*/
|
||||
|
||||
import { DeepSeekLLM } from "../src/llms/deepseek";
|
||||
|
||||
const mockCreate = jest.fn();
|
||||
|
||||
jest.mock("openai", () => {
|
||||
return jest.fn().mockImplementation(() => ({
|
||||
chat: { completions: { create: mockCreate } },
|
||||
}));
|
||||
});
|
||||
|
||||
describe("DeepSeekLLM (unit)", () => {
|
||||
beforeEach(() => mockCreate.mockClear());
|
||||
|
||||
it("throws when no API key is provided", () => {
|
||||
const original = process.env.DEEPSEEK_API_KEY;
|
||||
delete process.env.DEEPSEEK_API_KEY;
|
||||
try {
|
||||
expect(() => new DeepSeekLLM({})).toThrow("DeepSeek API key is required");
|
||||
} finally {
|
||||
if (original !== undefined) process.env.DEEPSEEK_API_KEY = original;
|
||||
}
|
||||
});
|
||||
|
||||
it("generateResponse() returns a text response", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
choices: [
|
||||
{
|
||||
message: {
|
||||
content: "Hello, world!",
|
||||
role: "assistant",
|
||||
tool_calls: null,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const llm = new DeepSeekLLM({ apiKey: "test-key" });
|
||||
const result = await llm.generateResponse([
|
||||
{ role: "user", content: "Hi" },
|
||||
]);
|
||||
|
||||
expect(mockCreate).toHaveBeenCalledTimes(1);
|
||||
expect(result).toBe("Hello, world!");
|
||||
});
|
||||
|
||||
it("generateResponse() handles tool calls", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
choices: [
|
||||
{
|
||||
message: {
|
||||
content: "",
|
||||
role: "assistant",
|
||||
tool_calls: [
|
||||
{
|
||||
function: {
|
||||
name: "get_weather",
|
||||
arguments: '{"city": "London"}',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const llm = new DeepSeekLLM({ apiKey: "test-key" });
|
||||
const result = await llm.generateResponse(
|
||||
[{ role: "user", content: "What is the weather?" }],
|
||||
undefined,
|
||||
[{ type: "function", function: { name: "get_weather" } }],
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
content: "",
|
||||
role: "assistant",
|
||||
toolCalls: [{ name: "get_weather", arguments: '{"city": "London"}' }],
|
||||
});
|
||||
});
|
||||
|
||||
it("generateResponse() wraps API errors with a clear message", async () => {
|
||||
mockCreate.mockRejectedValueOnce(new Error("Connection refused"));
|
||||
|
||||
const llm = new DeepSeekLLM({ apiKey: "test-key" });
|
||||
|
||||
await expect(
|
||||
llm.generateResponse([{ role: "user", content: "Hi" }]),
|
||||
).rejects.toThrow("DeepSeek LLM failed: Connection refused");
|
||||
});
|
||||
|
||||
it("generateChat() returns LLMResponse shape", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
choices: [
|
||||
{
|
||||
message: { content: "I can help with that.", role: "assistant" },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const llm = new DeepSeekLLM({ apiKey: "test-key" });
|
||||
const result = await llm.generateChat([
|
||||
{ role: "user", content: "Help me" },
|
||||
]);
|
||||
|
||||
expect(result).toEqual({
|
||||
content: "I can help with that.",
|
||||
role: "assistant",
|
||||
});
|
||||
});
|
||||
|
||||
it("generateChat() wraps API errors with a clear message", async () => {
|
||||
mockCreate.mockRejectedValueOnce(new Error("Timeout"));
|
||||
|
||||
const llm = new DeepSeekLLM({ apiKey: "test-key" });
|
||||
|
||||
await expect(
|
||||
llm.generateChat([{ role: "user", content: "Hi" }]),
|
||||
).rejects.toThrow("DeepSeek LLM failed: Timeout");
|
||||
});
|
||||
});
|
||||
@@ -87,6 +87,11 @@ jest.mock("../src/llms/lmstudio", () => ({
|
||||
.fn()
|
||||
.mockImplementation((config) => ({ type: "lmstudio-llm", config })),
|
||||
}));
|
||||
jest.mock("../src/llms/deepseek", () => ({
|
||||
DeepSeekLLM: jest
|
||||
.fn()
|
||||
.mockImplementation((config) => ({ type: "deepseek-llm", config })),
|
||||
}));
|
||||
|
||||
jest.mock("../src/vector_stores/qdrant", () => ({
|
||||
Qdrant: jest
|
||||
@@ -200,6 +205,7 @@ describe("LLMFactory", () => {
|
||||
["mistral"],
|
||||
["langchain"],
|
||||
["lmstudio"],
|
||||
["deepseek"],
|
||||
])("creates LLM for provider '%s'", (provider) => {
|
||||
expect(() => LLMFactory.create(provider, dummyLLMConfig)).not.toThrow();
|
||||
});
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
/// <reference types="jest" />
|
||||
/**
|
||||
* Telemetry sampling — unit tests.
|
||||
*
|
||||
* Sampling lives inside captureClientEvent in src/utils/telemetry.ts. It uses
|
||||
* Math.random() compared against MEM0_TELEMETRY_SAMPLE_RATE (default 0.1) to
|
||||
* drop hot-path events; lifecycle events ('init', 'reset') always fire.
|
||||
*
|
||||
* These tests target captureClientEvent directly. Existing OSS tests that mock
|
||||
* captureClientEvent (vector-stores-compat, dimension-autodetect, config-manager)
|
||||
* are unaffected because the function signature and contract are unchanged.
|
||||
*/
|
||||
|
||||
import type { TelemetryInstance } from "../src/utils/telemetry.types";
|
||||
|
||||
// Helper to make a fake TelemetryInstance.
|
||||
function makeInstance(
|
||||
overrides: Partial<TelemetryInstance> = {},
|
||||
): TelemetryInstance {
|
||||
return {
|
||||
telemetryId: "test-id",
|
||||
constructor: { name: "Memory" },
|
||||
host: "https://test.example.com",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe("telemetry sampling", () => {
|
||||
let originalFetch: typeof global.fetch;
|
||||
let fetchMock: jest.Mock;
|
||||
let randomSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
originalFetch = global.fetch;
|
||||
fetchMock = jest.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
text: jest.fn().mockResolvedValue(""),
|
||||
});
|
||||
global.fetch = fetchMock as any;
|
||||
randomSpy = jest.spyOn(Math, "random");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
global.fetch = originalFetch;
|
||||
randomSpy.mockRestore();
|
||||
jest.resetModules();
|
||||
});
|
||||
|
||||
describe("lifecycle events always fire", () => {
|
||||
it("init event fires even at the highest random value", async () => {
|
||||
randomSpy.mockReturnValue(0.999);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("init", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("reset event fires even at the highest random value", async () => {
|
||||
randomSpy.mockReturnValue(0.999);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("reset", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("init event payload has sample_rate: 1.0", async () => {
|
||||
randomSpy.mockReturnValue(0.999);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("init", makeInstance());
|
||||
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
||||
expect(body.properties.sample_rate).toBe(1.0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("hot-path events are sampled", () => {
|
||||
it("add event is dropped when random > sample_rate", async () => {
|
||||
randomSpy.mockReturnValue(0.99); // > 0.1 default rate
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("search event is dropped when random > sample_rate", async () => {
|
||||
randomSpy.mockReturnValue(0.99);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("search", makeInstance());
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("add event passes when random < sample_rate", async () => {
|
||||
randomSpy.mockReturnValue(0.05); // < 0.1 default rate
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("hot-path event payload has sample_rate: 0.1", async () => {
|
||||
randomSpy.mockReturnValue(0.05);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
||||
expect(body.properties.sample_rate).toBe(0.1);
|
||||
});
|
||||
|
||||
it("sample_rate cannot be overridden by additionalData", async () => {
|
||||
randomSpy.mockReturnValue(0.05);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance(), { sample_rate: 0.99 });
|
||||
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
||||
expect(body.properties.sample_rate).toBe(0.1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("env var override", () => {
|
||||
afterEach(() => {
|
||||
delete process.env.MEM0_TELEMETRY_SAMPLE_RATE;
|
||||
});
|
||||
|
||||
it("rate 1.0 sends every event including hot-path at high random", async () => {
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "1.0";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.999);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
// 0.999 > 1.0 is false, so the gate never trips
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("rate 0.0 drops every hot-path event including at random 0", async () => {
|
||||
// The gate is `random >= rate`, so rate=0 drops at random=0 (0 >= 0 is true).
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "0.0";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.0);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rate 0.0 drops at any random value", async () => {
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "0.0";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.5);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rate 0.0 still passes lifecycle events", async () => {
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "0.0";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.999);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("init", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("rate 0.5 passes events at random below 0.5", async () => {
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "0.5";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.3);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("invalid env var falls back to default rate", async () => {
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "not a number";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.05);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("out-of-range env var (negative) falls back to default rate", async () => {
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "-0.5";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.05);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("out-of-range env var (> 1) falls back to default rate", async () => {
|
||||
process.env.MEM0_TELEMETRY_SAMPLE_RATE = "5";
|
||||
jest.resetModules();
|
||||
randomSpy.mockReturnValue(0.05);
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance());
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("contract preservation", () => {
|
||||
it("lifecycle event includes additionalData", async () => {
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("init", makeInstance(), {
|
||||
api_version: "v1.1",
|
||||
client_type: "Memory",
|
||||
});
|
||||
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
||||
expect(body.properties.api_version).toBe("v1.1");
|
||||
expect(body.properties.client_type).toBe("Memory");
|
||||
expect(body.properties.sample_rate).toBe(1.0);
|
||||
});
|
||||
|
||||
it("captureClientEvent without telemetryId is a no-op", async () => {
|
||||
const { captureClientEvent } = await import("../src/utils/telemetry");
|
||||
await captureClientEvent("add", makeInstance({ telemetryId: "" }));
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,7 @@ import atexit
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
import random
|
||||
import sys
|
||||
import threading
|
||||
|
||||
@@ -22,16 +23,65 @@ if not isinstance(MEM0_TELEMETRY, bool):
|
||||
|
||||
logging.getLogger("posthog").setLevel(logging.CRITICAL + 1)
|
||||
logging.getLogger("urllib3").setLevel(logging.CRITICAL + 1)
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Default sampling rate for hot-path OSS events. Lifecycle events always fire at 100%.
|
||||
# Override via MEM0_TELEMETRY_SAMPLE_RATE env var.
|
||||
_DEFAULT_SAMPLE_RATE = 0.1
|
||||
|
||||
|
||||
def _parse_sample_rate(raw):
|
||||
"""Parse MEM0_TELEMETRY_SAMPLE_RATE env var. Never raises."""
|
||||
try:
|
||||
value = float(raw)
|
||||
except (TypeError, ValueError):
|
||||
_logger.debug("MEM0_TELEMETRY_SAMPLE_RATE %r is not a number, defaulting to %s", raw, _DEFAULT_SAMPLE_RATE)
|
||||
return _DEFAULT_SAMPLE_RATE
|
||||
if not 0.0 <= value <= 1.0:
|
||||
_logger.debug("MEM0_TELEMETRY_SAMPLE_RATE %s out of [0.0, 1.0], defaulting to %s", value, _DEFAULT_SAMPLE_RATE)
|
||||
return _DEFAULT_SAMPLE_RATE
|
||||
return value
|
||||
|
||||
|
||||
MEM0_TELEMETRY_SAMPLE_RATE = _parse_sample_rate(os.environ.get("MEM0_TELEMETRY_SAMPLE_RATE", str(_DEFAULT_SAMPLE_RATE)))
|
||||
|
||||
# Events that bypass sampling and always fire. Keep this set in sync with the
|
||||
# event names passed to capture_event() in mem0/memory/main.py.
|
||||
_LIFECYCLE_EVENTS = frozenset({"mem0.init", "mem0.reset", "mem0._create_procedural_memory"})
|
||||
|
||||
|
||||
def _sampling_before_send(msg):
|
||||
"""PostHog before_send hook: drop sampled hot-path events, annotate survivors with sample_rate."""
|
||||
if not isinstance(msg, dict):
|
||||
return None
|
||||
|
||||
event_name = msg.get("event", "")
|
||||
is_lifecycle = event_name in _LIFECYCLE_EVENTS
|
||||
|
||||
# >= so that rate=0 drops everything and rate=1 keeps everything (random ∈ [0, 1)).
|
||||
if not is_lifecycle and random.random() >= MEM0_TELEMETRY_SAMPLE_RATE:
|
||||
return None
|
||||
|
||||
# Annotate so PostHog dashboards can extrapolate true counts via 1/sample_rate.
|
||||
properties = msg.setdefault("properties", {})
|
||||
properties["sample_rate"] = 1.0 if is_lifecycle else MEM0_TELEMETRY_SAMPLE_RATE
|
||||
return msg
|
||||
|
||||
|
||||
class AnonymousTelemetry:
|
||||
def __init__(self, vector_store=None):
|
||||
def __init__(self, vector_store=None, before_send=None):
|
||||
if not MEM0_TELEMETRY:
|
||||
self.posthog = None
|
||||
self.user_id = None
|
||||
return
|
||||
|
||||
self.posthog = Posthog(project_api_key=PROJECT_API_KEY, host=HOST)
|
||||
try:
|
||||
self.posthog = Posthog(project_api_key=PROJECT_API_KEY, host=HOST, before_send=before_send)
|
||||
except TypeError:
|
||||
# posthog <4.5.0 does not accept before_send; fall back without sampling.
|
||||
_logger.debug("posthog.Posthog does not accept before_send; upgrade to >=4.5.0 for sampling")
|
||||
self.posthog = Posthog(project_api_key=PROJECT_API_KEY, host=HOST)
|
||||
self.user_id = get_or_create_user_id(vector_store)
|
||||
|
||||
def capture_event(self, event_name, properties=None, user_email=None):
|
||||
@@ -87,7 +137,7 @@ def _get_oss_telemetry():
|
||||
# Double-checked locking
|
||||
if _oss_telemetry_instance is not None:
|
||||
return _oss_telemetry_instance
|
||||
_oss_telemetry_instance = AnonymousTelemetry()
|
||||
_oss_telemetry_instance = AnonymousTelemetry(before_send=_sampling_before_send)
|
||||
atexit.register(_shutdown_oss_telemetry)
|
||||
return _oss_telemetry_instance
|
||||
|
||||
@@ -102,6 +152,7 @@ def _shutdown_oss_telemetry():
|
||||
|
||||
|
||||
# Module-level client telemetry singleton (used by capture_client_event).
|
||||
# No before_send — hosted MemoryClient traffic must never be sampled.
|
||||
client_telemetry = AnonymousTelemetry()
|
||||
atexit.register(client_telemetry.close)
|
||||
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to the `@mem0/openclaw-mem0` plugin will be documented in this file.
|
||||
|
||||
## [1.0.5] - 2026-04-07
|
||||
|
||||
### Fixed
|
||||
- **Init interactive choice bug**: Fixed number selection in `openclaw mem0 init` — entering 1/2/3 now correctly selects the corresponding option (was broken by readline prefill concatenating with user input)
|
||||
- **OSS pgvector crash** ([#4727]): Fixed "Client has already been connected" cascade when using pgvector in OSS mode. The warmup call swallowed errors leaving a half-initialized pg client; concurrent recall/capture then all hit `client.connect()` on the same client. Fix: let warmup errors propagate (so `initPromise` resets and retries with a fresh Memory + fresh pg client) and build fresh config objects per attempt instead of mutating shared state.
|
||||
|
||||
### Removed
|
||||
- **`orgId` / `projectId` config parameters**: Removed from config schema, CLI (`config show/get/set`), init display, and providers. The API key is project-scoped, so separate org/project IDs are unnecessary and could cause access errors if mismatched.
|
||||
- **`enableGraph` config parameter**: Removed from all config surfaces, providers, backend, and tools. Graph memory is being deprecated — removing the flag avoids unnecessary exposure.
|
||||
|
||||
## [1.0.4] - 2026-04-04
|
||||
|
||||
### Added
|
||||
- **Interactive init flow**: `openclaw mem0 init` with interactive menu (email verification or direct API key). Non-interactive modes: `--api-key`, `--email`, `--email --code`
|
||||
- **`memory_add` tool**: Replaces `memory_store` — name now matches `mem0` CLI and platform API
|
||||
- **`memory_delete` tool**: Unified delete — single ID, search-then-delete, bulk, entity cascade. Replaces `memory_forget` and `memory_delete_all`
|
||||
- **CLI subcommands**: `openclaw mem0 init`, `openclaw mem0 status` (renamed from `stats`), `openclaw mem0 config show`, `openclaw mem0 config set`
|
||||
- **`import` CLI command**: Bulk-import memories from a JSON file with `--user-id` and `--agent-id` overrides
|
||||
- **`event list` / `event status` CLI commands**: Monitor background processing events
|
||||
- **`fs-safe.ts` module**: Isolated filesystem wrappers (sync read/write/exists/mkdir/unlink) in a separate entry point — keeps file I/O out of the main bundle
|
||||
- **`backend/` module**: `PlatformBackend` with direct HTTP API access for CLI commands
|
||||
- **`cli/config-file.ts`**: Persistent plugin auth storage in `~/.openclaw/openclaw.json`
|
||||
- **Plugin manifest**: Added `contracts.tools`, `configSchema`, and `uiHints` to `openclaw.plugin.json`
|
||||
- **Test suite**: 329 tests across 10 test files covering tools, CLI, config, dream gate, providers, and skill-loader
|
||||
|
||||
### Changed
|
||||
- **Modular architecture**: Extracted tools into `tools/` directory (6 files) and CLI into `cli/commands.ts` — `index.ts` down from ~1700 to ~890 lines
|
||||
- **Code splitting**: tsup builds with `splitting: true` and two entry points (`index.ts`, `fs-safe.ts`), separating filesystem I/O from the main bundle
|
||||
- **Skills updated**: All SKILL.md files reference new tool names (`memory_add`, `memory_delete`) matching the plugin manifest
|
||||
- **WRITE_TOOLS updated**: Dream gate tracks `memory_delete` and `memory_add` instead of `memory_forget` and `memory_store`
|
||||
- **`mem0ai` dependency**: Updated from `2.3.0` to `2.4.5`
|
||||
- **Auto-recall timeout**: Recall wrapped in 8-second `Promise.race` — if the LLM takes too long, recall is skipped instead of stalling the gateway
|
||||
- **Auto-capture fire-and-forget**: `provider.add()` now runs in the background via `.then()/.catch()` — the `agent_end` hook returns immediately, zero event loop blocking
|
||||
- **Auto-capture minimum content gate**: Skips extraction when total user content is <50 chars after filtering — trivial conversations ("ok", "thanks") no longer trigger LLM calls
|
||||
- **CLI search**: Lowered threshold to 0.3 so explicit searches are more permissive than auto-recall
|
||||
- **Init defaults**: Choice defaults to `1` (email login) on Enter, User ID defaults to OS username — no more empty values
|
||||
- **Init no longer stores `baseUrl`**: Uses `https://api.mem0.ai` directly instead of persisting it to config
|
||||
- **Help output reordered**: `openclaw mem0 help` now shows high-value commands first (search, add) instead of alphabetical
|
||||
|
||||
### Removed
|
||||
- `memory_store` tool — replaced by `memory_add`
|
||||
- `memory_forget` tool — replaced by `memory_delete`
|
||||
- `memory_delete_all` tool — merged into `memory_delete`
|
||||
- `memory_history` tool and `history` CLI command — deprecated
|
||||
- **`custom_instructions` / `custom_categories` in `buildAddOptions`**: No longer injected into every auto-capture API call. Config fields (`customInstructions`, `customCategories`) remain as user-configurable options.
|
||||
|
||||
## [1.0.3] - 2026-04-03
|
||||
|
||||
### Fixed
|
||||
- **Path traversal vulnerability**: Added `safePath()` containment helper to `readSkillFile` and `readDomainOverlay` in `skill-loader.ts` — prevents directory traversal via `config.domain` or the exported `loadSkill` API
|
||||
- **Noise filter regression**: Reverted incorrect `After-Compaction` regex rename back to `Post-Compaction` so the filter correctly matches real upstream compaction audit messages
|
||||
- **Cosmetic revert**: Restored `// Over-fetch for ranking` comment in `recall.ts` (was changed to work around a false-positive scanner match on the substring `fetch`)
|
||||
|
||||
### Changed
|
||||
- **Supply-chain hardening**: Pinned `mem0ai` dependency to exact `2.3.0` (was `^2.3.0`)
|
||||
|
||||
### Added
|
||||
- **Path traversal tests**: 12 new tests covering `safePath`, `readSkillFile`, `readDomainOverlay`, and `loadSkill` with traversal inputs
|
||||
|
||||
## [1.0.2] - 2026-04-02
|
||||
|
||||
### Fixed
|
||||
- **Security scanner warning**: Removed `resolveEnvVars()` and `resolveEnvVarsDeep()` from `config.ts` — OpenClaw already resolves `${VAR}` in `openclaw.json` before passing config to the plugin, so plugin-side env resolution was redundant and triggered the "credential harvesting" static analysis warning ([#4676](https://github.com/mem0ai/mem0/pull/4676))
|
||||
|
||||
## [1.0.1] - 2026-04-02
|
||||
|
||||
### Added
|
||||
- **CD workflow**: Added continuous deployment workflow for `@mem0/openclaw-mem0` with OIDC trusted publishing ([#4672](https://github.com/mem0ai/mem0/pull/4672))
|
||||
- **Plugin configuration manifest**: Added `compat` and `build` metadata to `package.json` specifying minimum gateway version and OpenClaw SDK compatibility (`>=2026.3.24-beta.2`) ([#4667](https://github.com/mem0ai/mem0/pull/4667))
|
||||
- **LICENSE**: Added Apache-2.0 license file to the package ([#4667](https://github.com/mem0ai/mem0/pull/4667))
|
||||
|
||||
### Fixed
|
||||
- **Dream gate correctness**: Fixed cheap-first ordering, session isolation, and verified completion in the dream gate memory consolidation pipeline ([#4666](https://github.com/mem0ai/mem0/pull/4666))
|
||||
- **Graceful startup without API key**: Plugin now starts gracefully when no API key is configured instead of crashing on init ([#4669](https://github.com/mem0ai/mem0/pull/4669))
|
||||
|
||||
## [1.0.0] - 2026-04-01
|
||||
|
||||
### Added
|
||||
- **Skills-based memory architecture**: New skill-loader and skill-based extraction pipeline with batched extraction for higher quality memory capture ([#4624](https://github.com/mem0ai/mem0/pull/4624))
|
||||
- **Dream gate**: Added `dream-gate.ts` for memory consolidation and dream-cycle processing
|
||||
- **Enhanced recall**: New `recall.ts` module with improved recall logic and skill-aware retrieval
|
||||
- **Memory triage skill**: Domain-aware memory triage with companion domain support and recall protocol
|
||||
- **Memory dream skill**: Skill for memory consolidation during idle periods
|
||||
- **Plugin configuration**: Added `openclaw.plugin.json` manifest and `scripts/configure.py` setup helper
|
||||
|
||||
### Changed
|
||||
- Extraction pipeline refactored to use skills-based architecture for more contextual and higher quality memory capture
|
||||
|
||||
## [0.4.1] - 2026-03-26
|
||||
|
||||
### Added
|
||||
- **Improved extraction quality**: Enhanced noise filtering, deduplication, and better extraction instructions for higher-quality memory capture (#4302)
|
||||
|
||||
### Fixed
|
||||
- **Credential detection in extraction**: Improved detection of credentials, API keys, and secrets in extraction instructions to prevent them from being stored as memories (#4552)
|
||||
- **Standalone timestamp extraction**: Prevented extraction of standalone timestamps as memories when no meaningful content accompanies them (#4550)
|
||||
|
||||
## [0.4.0] - 2026-03-16
|
||||
|
||||
### Added
|
||||
- **Non-interactive trigger filtering**: Skips recall and capture for `cron`, `heartbeat`, `automation`, and `schedule` triggers — prevents system-generated noise from polluting memory
|
||||
- **Subagent hallucination prevention**: `isSubagentSession()` detects ephemeral subagent sessions and routes recall to the parent (main user) namespace instead of empty ephemeral namespaces; skips capture to prevent orphaned memories
|
||||
- **Subagent-specific preamble**: Subagents receive "You are a subagent — use these memories for context but do not assume you are this user" to prevent identity assumption
|
||||
- **User identity in recall preamble**: Recalled memories now include `userId` attribution for better context
|
||||
- **User identity in extraction preamble**: Extraction context includes user identity and current date for accurate attribution and temporal anchoring
|
||||
- **User-content guard**: Skips extraction when no meaningful user messages remain after filtering
|
||||
- **Dynamic recall thresholding**: Memories scoring less than 50% of the top result are dropped to filter out the long tail of weak matches
|
||||
- **SQLite resilience for OSS mode**: Init error recovery with automatic retry (history disabled) when native SQLite bindings fail under jiti
|
||||
- **`disableHistory` config option**: New `oss.disableHistory` flag to explicitly skip history DB initialization
|
||||
- **Updated minimum package version of mem0ai package**: Updated minimum package version of mem0ai package to ^2.3.0 to force old users to migrate to better-sqlite3
|
||||
- 78 unit tests covering filtering, isolation, trigger filtering, subagent detection, and SQLite resilience
|
||||
|
||||
### Changed
|
||||
- Auto-recall threshold raised from 0.5 to 0.6 for stricter precision during automatic injection (explicit tool searches remain at 0.5)
|
||||
- Recall candidate pool increased to `topK * 2` for better filtering headroom
|
||||
- Provider init promises now reset on failure, allowing retry on subsequent calls
|
||||
- Relaxed extraction instructions: related facts are kept together to preserve context (removed atomic memory requirement)
|
||||
|
||||
### Fixed
|
||||
- **Concurrent session race condition**: Lifecycle hooks (`before_agent_start`, `agent_end`) now use `ctx.sessionKey` directly from the event context instead of a shared mutable `currentSessionId` variable, preventing cross-session data leaks when multiple sessions run simultaneously
|
||||
|
||||
## [0.3.1] - 2026-03-12
|
||||
|
||||
### Added
|
||||
- **Message filtering pipeline**: Multi-stage noise removal before extraction — drops heartbeats, timestamps, single-word acks, system routing metadata, compaction audit logs, and generic assistant acknowledgments
|
||||
- **Broad recall for new sessions**: Short or new-session prompts trigger a secondary broad search to avoid cold-start blindness
|
||||
- **Client-side threshold filtering**: Safety net that drops low-relevance results even if the API doesn't honor the threshold parameter
|
||||
- **Temporal anchoring**: Extraction instructions now include current date so memories are prefixed with "As of YYYY-MM-DD, ..."
|
||||
- **Summary message inclusion**: Earlier assistant messages containing work summaries are included in extraction context even if outside the recent-message window
|
||||
- 55 unit tests covering filtering and isolation helpers
|
||||
|
||||
### Changed
|
||||
- Default `searchThreshold` remains at 0.5, with client-side filtering as a safety net
|
||||
- Extraction window expanded from last 10 → last 20 messages for richer context
|
||||
- Rewritten custom extraction instructions: conciseness, outcome-over-intent, deduplication guidance, language preservation
|
||||
- **Refactored** monolithic `index.ts` (1772 lines) into 6 focused modules: `types.ts`, `providers.ts`, `config.ts`, `filtering.ts`, `isolation.ts`, `index.ts`
|
||||
|
||||
### Fixed
|
||||
- **README image on npmjs.com**: Changed architecture diagram from relative path to absolute GitHub URL so it renders correctly on the npm registry
|
||||
|
||||
## [0.3.0] - 2026-03-10
|
||||
|
||||
### Fixed
|
||||
- Updated `mem0ai` dependency which includes the sqlite3 to better-sqlite3 migration for native binding resolution (#4270)
|
||||
|
||||
## [0.2.0] - 2026-03-09
|
||||
|
||||
### Added
|
||||
- "Understanding userId" section in docs clarifying that `userId` is user-defined
|
||||
- Per-agent memory isolation for multi-agent setups via `agentId`
|
||||
- Regression tests for per-agent isolation helpers
|
||||
|
||||
### Changed
|
||||
- Updated config examples to use concrete `userId` values instead of placeholders
|
||||
|
||||
### Fixed
|
||||
- Migrated platform search to Mem0 v2 API
|
||||
|
||||
## [0.1.2] - 2026-02-19
|
||||
|
||||
### Added
|
||||
- Source field for openclaw memory entries
|
||||
|
||||
### Fixed
|
||||
- Auto-recall injection and auto-capture message drop
|
||||
|
||||
## [0.1.0] - 2026-02-02
|
||||
|
||||
### Added
|
||||
- Initial release of the OpenClaw Mem0 plugin
|
||||
- Platform mode (Mem0 Cloud) and open-source mode support
|
||||
- Auto-recall: inject relevant memories before each turn
|
||||
- Auto-capture: store facts after each turn
|
||||
- Configurable `topK`, `threshold`, and `apiVersion` options
|
||||
+6
-6
@@ -17,7 +17,7 @@ dependencies = [
|
||||
"qdrant-client>=1.9.1",
|
||||
"pydantic>=2.7.3",
|
||||
"openai>=1.90.0",
|
||||
"posthog>=3.5.0",
|
||||
"posthog>=4.5.0",
|
||||
"pytz>=2024.1",
|
||||
"sqlalchemy>=2.0.31",
|
||||
"protobuf>=5.29.6,<7.0.0",
|
||||
@@ -33,7 +33,7 @@ graph = [
|
||||
"kuzu>=0.11.0",
|
||||
"apache-age-python>=0.0.6",
|
||||
]
|
||||
vector_stores = [
|
||||
vector-stores = [
|
||||
"vecs>=0.4.0",
|
||||
"chromadb>=0.4.24",
|
||||
"cassandra-driver>=3.29.0",
|
||||
@@ -108,7 +108,7 @@ python = "3.9"
|
||||
features = [
|
||||
"test",
|
||||
"graph",
|
||||
"vector_stores",
|
||||
"vector-stores",
|
||||
"llms",
|
||||
"extras",
|
||||
]
|
||||
@@ -118,7 +118,7 @@ python = "3.10"
|
||||
features = [
|
||||
"test",
|
||||
"graph",
|
||||
"vector_stores",
|
||||
"vector-stores",
|
||||
"llms",
|
||||
"extras",
|
||||
]
|
||||
@@ -128,7 +128,7 @@ python = "3.11"
|
||||
features = [
|
||||
"test",
|
||||
"graph",
|
||||
"vector_stores",
|
||||
"vector-stores",
|
||||
"llms",
|
||||
"extras",
|
||||
]
|
||||
@@ -138,7 +138,7 @@ python = "3.12"
|
||||
features = [
|
||||
"test",
|
||||
"graph",
|
||||
"vector_stores",
|
||||
"vector-stores",
|
||||
"llms",
|
||||
"extras",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
"""Tests for OSS telemetry sampling.
|
||||
|
||||
Tests target _sampling_before_send and its wiring directly. Existing tests in
|
||||
test_telemetry.py cover opt-out, singleton, and lifecycle behavior and are
|
||||
unaffected by sampling.
|
||||
"""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
import mem0.memory.telemetry as telemetry_module
|
||||
|
||||
|
||||
class TestParseSampleRate:
|
||||
"""Verify the env var parsing helper. Must never raise."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"raw,expected",
|
||||
[
|
||||
("0.0", 0.0),
|
||||
("0.1", 0.1),
|
||||
("0.5", 0.5),
|
||||
("1.0", 1.0),
|
||||
("0.05", 0.05),
|
||||
],
|
||||
)
|
||||
def test_valid_values(self, raw, expected):
|
||||
assert telemetry_module._parse_sample_rate(raw) == expected
|
||||
|
||||
@pytest.mark.parametrize("raw", ["abc", "", "5.0", "-1", "-0.5", "1.5", "2", "nan"])
|
||||
def test_invalid_values_fall_back_to_default(self, raw):
|
||||
assert telemetry_module._parse_sample_rate(raw) == telemetry_module._DEFAULT_SAMPLE_RATE
|
||||
|
||||
def test_none_falls_back(self):
|
||||
assert telemetry_module._parse_sample_rate(None) == telemetry_module._DEFAULT_SAMPLE_RATE
|
||||
|
||||
|
||||
class TestSamplingBeforeSend:
|
||||
"""Verify _sampling_before_send: the PostHog hook that drops/keeps events."""
|
||||
|
||||
def _msg(self, event_name, properties=None):
|
||||
return {"event": event_name, "properties": properties or {}}
|
||||
|
||||
def test_lifecycle_event_passes_through_at_high_random(self):
|
||||
"""Lifecycle events always fire even when random is near 1.0."""
|
||||
with patch("mem0.memory.telemetry.random.random", return_value=0.999):
|
||||
for event in ("mem0.init", "mem0.reset", "mem0._create_procedural_memory"):
|
||||
result = telemetry_module._sampling_before_send(self._msg(event))
|
||||
assert result is not None
|
||||
assert result["properties"]["sample_rate"] == 1.0
|
||||
|
||||
def test_hot_path_event_dropped_when_random_above_rate(self):
|
||||
"""At default rate 0.1, random=0.99 should drop the event."""
|
||||
with patch.object(telemetry_module, "MEM0_TELEMETRY_SAMPLE_RATE", 0.1):
|
||||
with patch("mem0.memory.telemetry.random.random", return_value=0.99):
|
||||
assert telemetry_module._sampling_before_send(self._msg("mem0.add")) is None
|
||||
|
||||
def test_hot_path_event_passes_when_random_below_rate(self):
|
||||
"""At default rate 0.1, random=0.05 should pass the event through."""
|
||||
with patch.object(telemetry_module, "MEM0_TELEMETRY_SAMPLE_RATE", 0.1):
|
||||
with patch("mem0.memory.telemetry.random.random", return_value=0.05):
|
||||
result = telemetry_module._sampling_before_send(self._msg("mem0.add"))
|
||||
assert result is not None
|
||||
assert result["properties"]["sample_rate"] == 0.1
|
||||
|
||||
def test_hot_path_annotates_sample_rate(self):
|
||||
with patch.object(telemetry_module, "MEM0_TELEMETRY_SAMPLE_RATE", 0.1):
|
||||
with patch("mem0.memory.telemetry.random.random", return_value=0.0):
|
||||
result = telemetry_module._sampling_before_send(self._msg("mem0.search"))
|
||||
assert result["properties"]["sample_rate"] == 0.1
|
||||
|
||||
def test_lifecycle_annotates_sample_rate_one(self):
|
||||
result = telemetry_module._sampling_before_send(self._msg("mem0.init"))
|
||||
assert result["properties"]["sample_rate"] == 1.0
|
||||
|
||||
def test_rate_zero_drops_all_hot_path(self):
|
||||
with patch.object(telemetry_module, "MEM0_TELEMETRY_SAMPLE_RATE", 0.0):
|
||||
# Gate is `random >= rate`, so 0.0 >= 0.0 → drop. random ∈ [0, 1) means
|
||||
# rate=0 drops every event.
|
||||
with patch("mem0.memory.telemetry.random.random", return_value=0.0):
|
||||
assert telemetry_module._sampling_before_send(self._msg("mem0.add")) is None
|
||||
|
||||
def test_rate_zero_still_passes_lifecycle(self):
|
||||
with patch.object(telemetry_module, "MEM0_TELEMETRY_SAMPLE_RATE", 0.0):
|
||||
with patch("mem0.memory.telemetry.random.random", return_value=0.999):
|
||||
assert telemetry_module._sampling_before_send(self._msg("mem0.init")) is not None
|
||||
|
||||
def test_rate_one_passes_all_events(self):
|
||||
with patch.object(telemetry_module, "MEM0_TELEMETRY_SAMPLE_RATE", 1.0):
|
||||
with patch("mem0.memory.telemetry.random.random", return_value=0.999):
|
||||
# 0.999 > 1.0 is False, so the gate never trips
|
||||
assert telemetry_module._sampling_before_send(self._msg("mem0.add")) is not None
|
||||
|
||||
def test_does_not_override_caller_supplied_sample_rate_for_hot_path(self):
|
||||
"""If a caller pre-populates sample_rate, our value still wins (we're authoritative)."""
|
||||
with patch.object(telemetry_module, "MEM0_TELEMETRY_SAMPLE_RATE", 0.1):
|
||||
with patch("mem0.memory.telemetry.random.random", return_value=0.0):
|
||||
msg = self._msg("mem0.add", {"sample_rate": 0.99, "other": "x"})
|
||||
result = telemetry_module._sampling_before_send(msg)
|
||||
assert result["properties"]["sample_rate"] == 0.1
|
||||
assert result["properties"]["other"] == "x"
|
||||
|
||||
def test_handles_missing_properties_dict(self):
|
||||
"""If a msg arrives without a properties key, we create it before annotating."""
|
||||
msg = {"event": "mem0.init"} # no properties
|
||||
result = telemetry_module._sampling_before_send(msg)
|
||||
assert result is not None
|
||||
assert result["properties"]["sample_rate"] == 1.0
|
||||
|
||||
def test_handles_missing_event_field(self):
|
||||
"""Defensive: a msg with no event field is treated as a hot-path event (gets sampled)."""
|
||||
with patch.object(telemetry_module, "MEM0_TELEMETRY_SAMPLE_RATE", 0.1):
|
||||
with patch("mem0.memory.telemetry.random.random", return_value=0.99):
|
||||
# event is missing -> treated as hot-path -> dropped at high random
|
||||
assert telemetry_module._sampling_before_send({"properties": {}}) is None
|
||||
|
||||
def test_handles_non_dict_input(self):
|
||||
"""Defensive: if PostHog ever passes us a non-dict, we drop the event."""
|
||||
assert telemetry_module._sampling_before_send("not a dict") is None
|
||||
assert telemetry_module._sampling_before_send(None) is None
|
||||
assert telemetry_module._sampling_before_send(42) is None
|
||||
assert telemetry_module._sampling_before_send(["list"]) is None
|
||||
|
||||
|
||||
class TestBeforeSendWiring:
|
||||
"""Verify the hook is wired into the OSS singleton but NOT client_telemetry."""
|
||||
|
||||
def setup_method(self):
|
||||
telemetry_module._oss_telemetry_instance = None
|
||||
telemetry_module._oss_telemetry_shutting_down = False
|
||||
|
||||
def teardown_method(self):
|
||||
telemetry_module._oss_telemetry_instance = None
|
||||
telemetry_module._oss_telemetry_shutting_down = False
|
||||
|
||||
def test_oss_singleton_constructed_with_before_send_hook(self):
|
||||
"""_get_oss_telemetry() should pass _sampling_before_send to AnonymousTelemetry."""
|
||||
with patch.object(telemetry_module, "MEM0_TELEMETRY", True):
|
||||
with patch("mem0.memory.telemetry.Posthog") as mock_posthog_cls:
|
||||
with patch("mem0.memory.telemetry.get_or_create_user_id", return_value="u"):
|
||||
with patch("atexit.register"):
|
||||
telemetry_module._get_oss_telemetry()
|
||||
# Verify Posthog() was constructed with before_send=_sampling_before_send
|
||||
_, kwargs = mock_posthog_cls.call_args
|
||||
assert kwargs.get("before_send") is telemetry_module._sampling_before_send
|
||||
|
||||
def test_client_telemetry_constructed_without_before_send(self):
|
||||
"""The module-level client_telemetry must NOT receive before_send.
|
||||
|
||||
client_telemetry is created at import time, so this test verifies the
|
||||
existing instance has no sampling hook attached to its underlying Posthog.
|
||||
"""
|
||||
# client_telemetry is created at module import time. We verify the
|
||||
# construction call site by re-constructing AnonymousTelemetry() the
|
||||
# same way and checking the kwargs.
|
||||
with patch.object(telemetry_module, "MEM0_TELEMETRY", True):
|
||||
with patch("mem0.memory.telemetry.Posthog") as mock_posthog_cls:
|
||||
with patch("mem0.memory.telemetry.get_or_create_user_id", return_value="u"):
|
||||
telemetry_module.AnonymousTelemetry() # mirrors client_telemetry construction
|
||||
_, kwargs = mock_posthog_cls.call_args
|
||||
# before_send is None (default), not _sampling_before_send
|
||||
assert kwargs.get("before_send") is None
|
||||
|
||||
def test_anonymous_telemetry_falls_back_when_posthog_rejects_before_send(self):
|
||||
"""If posthog (older version) rejects before_send, construction still succeeds."""
|
||||
with patch.object(telemetry_module, "MEM0_TELEMETRY", True):
|
||||
with patch("mem0.memory.telemetry.Posthog") as mock_posthog_cls:
|
||||
with patch("mem0.memory.telemetry.get_or_create_user_id", return_value="u"):
|
||||
# First call (with before_send) raises TypeError; second call succeeds.
|
||||
mock_posthog_cls.side_effect = [TypeError("unexpected kwarg before_send"), object()]
|
||||
at = telemetry_module.AnonymousTelemetry(before_send=telemetry_module._sampling_before_send)
|
||||
# Constructor was called twice: once with before_send, once without
|
||||
assert mock_posthog_cls.call_count == 2
|
||||
assert at.posthog is not None
|
||||
|
||||
|
||||
class TestSamplingDoesNotBreakExistingBehavior:
|
||||
"""Regression checks: sampling must be invisible above the SDK boundary."""
|
||||
|
||||
def setup_method(self):
|
||||
telemetry_module._oss_telemetry_instance = None
|
||||
telemetry_module._oss_telemetry_shutting_down = False
|
||||
|
||||
def teardown_method(self):
|
||||
telemetry_module._oss_telemetry_instance = None
|
||||
telemetry_module._oss_telemetry_shutting_down = False
|
||||
|
||||
def test_capture_event_signature_unchanged(self):
|
||||
"""The public capture_event() function still accepts the same args."""
|
||||
from inspect import signature
|
||||
|
||||
params = list(signature(telemetry_module.capture_event).parameters)
|
||||
assert params == ["event_name", "memory_instance", "additional_data"]
|
||||
|
||||
def test_capture_client_event_signature_unchanged(self):
|
||||
from inspect import signature
|
||||
|
||||
params = list(signature(telemetry_module.capture_client_event).parameters)
|
||||
assert params == ["event_name", "instance", "additional_data"]
|
||||
|
||||
def test_default_sample_rate_is_ten_percent(self):
|
||||
"""Module loads with the documented default."""
|
||||
# We can't assert MEM0_TELEMETRY_SAMPLE_RATE directly because the user
|
||||
# may have set the env var, so assert the default constant instead.
|
||||
assert telemetry_module._DEFAULT_SAMPLE_RATE == 0.1
|
||||
Reference in New Issue
Block a user