From 3d3e875d21a2d2641433484f3d45f3ac0715dc03 Mon Sep 17 00:00:00 2001 From: Deshraj Yadav Date: Mon, 2 Feb 2026 10:04:08 -0800 Subject: [PATCH] Feature: Add OpenClaw plugin and documentation (#3964) --- docs/docs.json | 55 +- docs/images/openclaw-architecture.png | Bin 0 -> 124646 bytes docs/integrations/openclaw.mdx | 172 +++ openclaw/.gitignore | 3 + openclaw/README.md | 155 +++ openclaw/index.ts | 1381 +++++++++++++++++++++++++ openclaw/openclaw.plugin.json | 168 +++ openclaw/package.json | 23 + 8 files changed, 1944 insertions(+), 13 deletions(-) create mode 100644 docs/images/openclaw-architecture.png create mode 100644 docs/integrations/openclaw.mdx create mode 100644 openclaw/.gitignore create mode 100644 openclaw/README.md create mode 100644 openclaw/index.ts create mode 100644 openclaw/openclaw.plugin.json create mode 100644 openclaw/package.json diff --git a/docs/docs.json b/docs/docs.json index 302b151a3..775baf364 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -29,7 +29,9 @@ { "group": "Start Here", "icon": "home", - "pages": ["introduction"] + "pages": [ + "introduction" + ] } ] }, @@ -112,7 +114,9 @@ { "group": "Support & Troubleshooting", "icon": "life-buoy", - "pages": ["platform/faqs"] + "pages": [ + "platform/faqs" + ] }, { "group": "Migration Guide", @@ -127,7 +131,9 @@ { "group": "Contribute", "icon": "clipboard-list", - "pages": ["platform/contribute"] + "pages": [ + "platform/contribute" + ] } ] }, @@ -282,7 +288,10 @@ { "group": "Community & Support", "icon": "users", - "pages": ["contributing/development", "contributing/documentation"] + "pages": [ + "contributing/development", + "contributing/documentation" + ] } ] }, @@ -306,7 +315,9 @@ { "group": "Getting Started", "icon": "lightbulb", - "pages": ["cookbooks/overview"] + "pages": [ + "cookbooks/overview" + ] }, { "group": "Essentials", @@ -378,7 +389,9 @@ { "group": "Overview", "icon": "plug", - "pages": ["integrations"] + "pages": [ + "integrations" + ] }, { "group": "Agent Frameworks", @@ -409,7 +422,9 @@ { "group": "Cloud & Infrastructure", "icon": "cloud", - "pages": ["integrations/aws-bedrock"] + "pages": [ + "integrations/aws-bedrock" + ] }, { "group": "Developer Tools", @@ -431,7 +446,10 @@ { "group": "Getting Started", "icon": "rocket", - "pages": ["api-reference", "api-reference/organizations-projects"] + "pages": [ + "api-reference", + "api-reference/organizations-projects" + ] }, { "group": "Core Memory Operations", @@ -461,7 +479,10 @@ { "group": "Events APIs", "icon": "clock", - "pages": ["api-reference/events/get-events", "api-reference/events/get-event"] + "pages": [ + "api-reference/events/get-events", + "api-reference/events/get-event" + ] }, { "group": "Entities APIs", @@ -513,12 +534,16 @@ { "group": "Changelog", "icon": "rocket", - "pages": ["changelog"] + "pages": [ + "changelog" + ] }, { "group": "Legacy Docs", "icon": "archive", - "pages": ["v0x/introduction"] + "pages": [ + "v0x/introduction" + ] } ] } @@ -539,7 +564,11 @@ { "group": "Getting Started", "icon": "rocket", - "pages": ["v0x/introduction", "v0x/quickstart", "v0x/faqs"] + "pages": [ + "v0x/introduction", + "v0x/quickstart", + "v0x/faqs" + ] }, { "group": "Core Concepts", @@ -1050,4 +1079,4 @@ "destination": "/platform/features/memory-export" } ] -} +} \ No newline at end of file diff --git a/docs/images/openclaw-architecture.png b/docs/images/openclaw-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..2baec5a6c8d6c327551de926c70b6151165368b9 GIT binary patch literal 124646 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 + OpenClaw Mem0 Architecture + + +The plugin provides: +1. **Auto-Recall** — Before the agent responds, memories matching the current message are injected into context +2. **Auto-Capture** — After the agent responds, the exchange is sent to Mem0 which decides what's worth keeping +3. **Agent Tools** — Five tools for explicit memory operations during conversations + +Both auto-recall and auto-capture run silently with no manual configuration required. + +## Installation + +```bash +openclaw plugins install @mem0/openclaw-mem0 +``` + +## Setup and Configuration + +### Platform Mode (Mem0 Cloud) + +Get your API key from [app.mem0.ai](https://app.mem0.ai). + +Add to your `openclaw.json`: + +```json5 +// plugins.entries +"openclaw-mem0": { + "enabled": true, + "config": { + "apiKey": "${MEM0_API_KEY}", + "userId": "your-user-id" + } +} +``` + +### Open-Source Mode (Self-hosted) + +No Mem0 key needed. Requires `OPENAI_API_KEY` for default embeddings/LLM. + +```json5 +"openclaw-mem0": { + "enabled": true, + "config": { + "mode": "open-source", + "userId": "your-user-id" + } +} +``` + +Sensible defaults work out of the box. To customize the embedder, vector store, or LLM: + +```json5 +"config": { + "mode": "open-source", + "userId": "your-user-id", + "oss": { + "embedder": { "provider": "openai", "config": { "model": "text-embedding-3-small" } }, + "vectorStore": { "provider": "qdrant", "config": { "host": "localhost", "port": 6333 } }, + "llm": { "provider": "openai", "config": { "model": "gpt-4o" } } + } +} +``` + +All `oss` fields are optional. See [Mem0 OSS docs](/open-source/node-quickstart) for available providers. + +## Short-term vs Long-term Memory + +Memories are organized into two scopes: + +- **Session (short-term)** — Auto-capture stores memories scoped to the current session via Mem0's `run_id` / `runId` parameter. These are contextual to the ongoing conversation. + +- **User (long-term)** — The agent can explicitly store long-term memories using the `memory_store` tool (with `longTerm: true`, the default). These persist across all sessions for the user. + +During **auto-recall**, the plugin searches both scopes and presents them separately — long-term memories first, then session memories — so the agent has full context. + +## Agent Tools + +The agent gets five tools it can call during conversations: + +| Tool | Description | +|------|-------------| +| `memory_search` | Search memories by natural language | +| `memory_list` | List all stored memories for a user | +| `memory_store` | Explicitly save a fact | +| `memory_get` | Retrieve a memory by ID | +| `memory_forget` | Delete by ID or by query | + +The `memory_search` and `memory_list` tools accept a `scope` parameter (`"session"`, `"long-term"`, or `"all"`) to control which memories are queried. The `memory_store` tool accepts a `longTerm` boolean (default: `true`) to choose where to store. + +## CLI Commands + +```bash +# Search all memories (long-term + session) +openclaw mem0 search "what languages does the user know" + +# Search only long-term memories +openclaw mem0 search "what languages does the user know" --scope long-term + +# Search only session/short-term memories +openclaw mem0 search "what languages does the user know" --scope session + +# View stats +openclaw mem0 stats +``` + +## Configuration Options + +### General Options + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| `mode` | `"platform"` \| `"open-source"` | `"platform"` | Which backend to use | +| `userId` | `string` | `"default"` | Scope memories per user | +| `autoRecall` | `boolean` | `true` | Inject memories before each turn | +| `autoCapture` | `boolean` | `true` | Store facts after each turn | +| `topK` | `number` | `5` | Max memories per recall | +| `searchThreshold` | `number` | `0.3` | Min similarity (0–1) | + +### Platform Mode Options + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| `apiKey` | `string` | — | **Required.** Mem0 API key (supports `${MEM0_API_KEY}`) | +| `orgId` | `string` | — | Organization ID | +| `projectId` | `string` | — | Project ID | +| `enableGraph` | `boolean` | `false` | Entity graph for relationships | +| `customInstructions` | `string` | *(built-in)* | Extraction rules — what to store, how to format | +| `customCategories` | `object` | *(12 defaults)* | Category name → description map for tagging | + +### Open-Source Mode Options + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| `customPrompt` | `string` | *(built-in)* | Extraction prompt for memory processing | +| `oss.embedder.provider` | `string` | `"openai"` | Embedding provider (`"openai"`, `"ollama"`, etc.) | +| `oss.embedder.config` | `object` | — | Provider config: `apiKey`, `model`, `baseURL` | +| `oss.vectorStore.provider` | `string` | `"memory"` | Vector store (`"memory"`, `"qdrant"`, `"chroma"`, etc.) | +| `oss.vectorStore.config` | `object` | — | Provider config: `host`, `port`, `collectionName`, `dimension` | +| `oss.llm.provider` | `string` | `"openai"` | LLM provider (`"openai"`, `"anthropic"`, `"ollama"`, etc.) | +| `oss.llm.config` | `object` | — | Provider config: `apiKey`, `model`, `baseURL`, `temperature` | +| `oss.historyDbPath` | `string` | — | SQLite path for memory edit history | + +Everything inside `oss` is optional — defaults use OpenAI embeddings (`text-embedding-3-small`), in-memory vector store, and OpenAI LLM. + +## Key Features + +1. **Zero Configuration** — Auto-recall and auto-capture work out of the box with no prompting required +2. **Dual Memory Scopes** — Session-scoped short-term and user-scoped long-term memories +3. **Flexible Backend** — Use Mem0 Cloud for managed service or self-host with open-source mode +4. **Rich Tool Suite** — Five agent tools for explicit memory operations when needed + +## Conclusion + +The `@mem0/openclaw-mem0` plugin gives OpenClaw agents persistent memory with minimal setup. Whether using Mem0 Cloud or self-hosting, your agents can now remember user preferences, facts, and context across sessions automatically. + + + + Build agents with OpenAI's SDK and Mem0 + + + Create stateful agent workflows with memory + + diff --git a/openclaw/.gitignore b/openclaw/.gitignore new file mode 100644 index 000000000..4913e17ad --- /dev/null +++ b/openclaw/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +package-lock.json +*.db diff --git a/openclaw/README.md b/openclaw/README.md new file mode 100644 index 000000000..3f939d9de --- /dev/null +++ b/openclaw/README.md @@ -0,0 +1,155 @@ +# @mem0/openclaw-mem0 + +Long-term memory for [OpenClaw](https://github.com/openclaw/openclaw) agents, powered by [Mem0](https://mem0.ai). + +Your agent forgets everything between sessions. This plugin fixes that. It watches conversations, extracts what matters, and brings it back when relevant — automatically. + +## How it works + +

+ Architecture +

+ +**Auto-Recall** — Before the agent responds, the plugin searches Mem0 for memories that match the current message and injects them into context. + +**Auto-Capture** — After the agent responds, the plugin sends the exchange to Mem0. Mem0 decides what's worth keeping — new facts get stored, stale ones updated, duplicates merged. + +Both run silently. No prompting, no configuration, no manual calls. + +### Short-term vs long-term memory + +Memories are organized into two scopes: + +- **Session (short-term)** — Auto-capture stores memories scoped to the current session via Mem0's `run_id` / `runId` parameter. These are contextual to the ongoing conversation and automatically recalled alongside long-term memories. + +- **User (long-term)** — The agent can explicitly store long-term memories using the `memory_store` tool (with `longTerm: true`, the default). These persist across all sessions for the user. + +During **auto-recall**, the plugin searches both scopes and presents them separately — long-term memories first, then session memories — so the agent has full context. + +The agent tools (`memory_search`, `memory_list`) accept a `scope` parameter (`"session"`, `"long-term"`, or `"all"`) to control which memories are queried. The `memory_store` tool accepts a `longTerm` boolean (default: `true`) to choose where to store. + +All new parameters are optional and backward-compatible — existing configurations work without changes. + +## Setup + +```bash +openclaw plugins install @mem0/openclaw-mem0 +``` + +### Platform (Mem0 Cloud) + +Get an API key from [app.mem0.ai](https://app.mem0.ai), then add to your `openclaw.json`: + +```json5 +// plugins.entries +"openclaw-mem0": { + "enabled": true, + "config": { + "apiKey": "${MEM0_API_KEY}", + "userId": "your-user-id" + } +} +``` + +### Open-Source (Self-hosted) + +No Mem0 key needed. Requires `OPENAI_API_KEY` for default embeddings/LLM. + +```json5 +"openclaw-mem0": { + "enabled": true, + "config": { + "mode": "open-source", + "userId": "your-user-id" + } +} +``` + +Sensible defaults out of the box. To customize the embedder, vector store, or LLM: + +```json5 +"config": { + "mode": "open-source", + "userId": "your-user-id", + "oss": { + "embedder": { "provider": "openai", "config": { "model": "text-embedding-3-small" } }, + "vectorStore": { "provider": "qdrant", "config": { "host": "localhost", "port": 6333 } }, + "llm": { "provider": "openai", "config": { "model": "gpt-4o" } } + } +} +``` + +All `oss` fields are optional. See [Mem0 OSS docs](https://docs.mem0.ai/open-source/node-quickstart) for providers. + +## Agent tools + +The agent gets five tools it can call during conversations: + +| Tool | Description | +|------|-------------| +| `memory_search` | Search memories by natural language | +| `memory_list` | List all stored memories for a user | +| `memory_store` | Explicitly save a fact | +| `memory_get` | Retrieve a memory by ID | +| `memory_forget` | Delete by ID or by query | + +## CLI + +```bash +# Search all memories (long-term + session) +openclaw mem0 search "what languages does the user know" + +# Search only long-term memories +openclaw mem0 search "what languages does the user know" --scope long-term + +# Search only session/short-term memories +openclaw mem0 search "what languages does the user know" --scope session + +# Stats +openclaw mem0 stats +``` + +## Options + +### General + +| Key | Type | Default | | +|-----|------|---------|---| +| `mode` | `"platform"` \| `"open-source"` | `"platform"` | Which backend to use | +| `userId` | `string` | `"default"` | Scope memories per user | +| `autoRecall` | `boolean` | `true` | Inject memories before each turn | +| `autoCapture` | `boolean` | `true` | Store facts after each turn | +| `topK` | `number` | `5` | Max memories per recall | +| `searchThreshold` | `number` | `0.3` | Min similarity (0–1) | + +### Platform mode + +| Key | Type | Default | | +|-----|------|---------|---| +| `apiKey` | `string` | — | **Required.** Mem0 API key (supports `${MEM0_API_KEY}`) | +| `orgId` | `string` | — | Organization ID | +| `projectId` | `string` | — | Project ID | +| `enableGraph` | `boolean` | `false` | Entity graph for relationships | +| `customInstructions` | `string` | *(built-in)* | Extraction rules — what to store, how to format | +| `customCategories` | `object` | *(12 defaults)* | Category name → description map for tagging | + +### Open-source mode + +Works with zero extra config. The `oss` block lets you swap out any component: + +| Key | Type | Default | | +|-----|------|---------|---| +| `customPrompt` | `string` | *(built-in)* | Extraction prompt for memory processing | +| `oss.embedder.provider` | `string` | `"openai"` | Embedding provider (`"openai"`, `"ollama"`, etc.) | +| `oss.embedder.config` | `object` | — | Provider config: `apiKey`, `model`, `baseURL` | +| `oss.vectorStore.provider` | `string` | `"memory"` | Vector store (`"memory"`, `"qdrant"`, `"chroma"`, etc.) | +| `oss.vectorStore.config` | `object` | — | Provider config: `host`, `port`, `collectionName`, `dimension` | +| `oss.llm.provider` | `string` | `"openai"` | LLM provider (`"openai"`, `"anthropic"`, `"ollama"`, etc.) | +| `oss.llm.config` | `object` | — | Provider config: `apiKey`, `model`, `baseURL`, `temperature` | +| `oss.historyDbPath` | `string` | — | SQLite path for memory edit history | + +Everything inside `oss` is optional — defaults use OpenAI embeddings (`text-embedding-3-small`), in-memory vector store, and OpenAI LLM. Override only what you need. + +## License + +Apache 2.0 diff --git a/openclaw/index.ts b/openclaw/index.ts new file mode 100644 index 000000000..09097761d --- /dev/null +++ b/openclaw/index.ts @@ -0,0 +1,1381 @@ +/** + * OpenClaw Memory (Mem0) Plugin + * + * Long-term memory via Mem0 — supports both the Mem0 platform + * and the open-source self-hosted SDK. Uses the official `mem0ai` package. + * + * Features: + * - 5 tools: memory_search, memory_list, memory_store, memory_get, memory_forget + * (with session/long-term scope support via scope and longTerm parameters) + * - Short-term (session-scoped) and long-term (user-scoped) memory + * - Auto-recall: injects relevant memories (both scopes) before each agent turn + * - Auto-capture: stores key facts scoped to the current session after each agent turn + * - CLI: openclaw mem0 search, openclaw mem0 stats + * - Dual mode: platform or open-source (self-hosted) + */ + +import { Type } from "@sinclair/typebox"; +import type { OpenClawPluginApi } from "openclaw/plugin-sdk"; + +// ============================================================================ +// Types +// ============================================================================ + +type Mem0Mode = "platform" | "open-source"; + +type Mem0Config = { + mode: Mem0Mode; + // Platform-specific + apiKey?: string; + orgId?: string; + projectId?: string; + customInstructions: string; + customCategories: Record; + enableGraph: boolean; + // OSS-specific + customPrompt?: string; + oss?: { + embedder?: { provider: string; config: Record }; + vectorStore?: { provider: string; config: Record }; + llm?: { provider: string; config: Record }; + historyDbPath?: string; + }; + // Shared + userId: string; + autoCapture: boolean; + autoRecall: boolean; + searchThreshold: number; + topK: number; +}; + +// Unified types for the provider interface +interface AddOptions { + user_id: string; + run_id?: string; + custom_instructions?: string; + custom_categories?: Array>; + enable_graph?: boolean; + output_format?: string; +} + +interface SearchOptions { + user_id: string; + run_id?: string; + top_k?: number; + threshold?: number; + limit?: number; + keyword_search?: boolean; + reranking?: boolean; +} + +interface ListOptions { + user_id: string; + run_id?: string; + page_size?: number; +} + +interface MemoryItem { + id: string; + memory: string; + user_id?: string; + score?: number; + categories?: string[]; + metadata?: Record; + created_at?: string; + updated_at?: string; +} + +interface AddResultItem { + id: string; + memory: string; + event: "ADD" | "UPDATE" | "DELETE" | "NOOP"; +} + +interface AddResult { + results: AddResultItem[]; +} + +// ============================================================================ +// Unified Provider Interface +// ============================================================================ + +interface Mem0Provider { + add( + messages: Array<{ role: string; content: string }>, + options: AddOptions, + ): Promise; + search(query: string, options: SearchOptions): Promise; + get(memoryId: string): Promise; + getAll(options: ListOptions): Promise; + delete(memoryId: string): Promise; +} + +// ============================================================================ +// Platform Provider (Mem0 Cloud) +// ============================================================================ + +class PlatformProvider implements Mem0Provider { + private client: any; // MemoryClient from mem0ai + private initPromise: Promise | null = null; + + constructor( + private readonly apiKey: string, + private readonly orgId?: string, + private readonly projectId?: string, + ) { } + + private async ensureClient(): Promise { + if (this.client) return; + if (this.initPromise) return this.initPromise; + this.initPromise = this._init(); + return this.initPromise; + } + + private async _init(): Promise { + const { default: MemoryClient } = await import("mem0ai"); + const opts: Record = { apiKey: this.apiKey }; + if (this.orgId) opts.org_id = this.orgId; + if (this.projectId) opts.project_id = this.projectId; + this.client = new MemoryClient(opts); + } + + async add( + messages: Array<{ role: string; content: string }>, + options: AddOptions, + ): Promise { + await this.ensureClient(); + const opts: Record = { user_id: options.user_id }; + if (options.run_id) opts.run_id = options.run_id; + if (options.custom_instructions) + opts.custom_instructions = options.custom_instructions; + if (options.custom_categories) + opts.custom_categories = options.custom_categories; + if (options.enable_graph) opts.enable_graph = options.enable_graph; + if (options.output_format) opts.output_format = options.output_format; + + const result = await this.client.add(messages, opts); + return normalizeAddResult(result); + } + + async search(query: string, options: SearchOptions): Promise { + await this.ensureClient(); + const opts: Record = { user_id: options.user_id }; + if (options.run_id) opts.run_id = options.run_id; + if (options.top_k != null) opts.top_k = options.top_k; + if (options.threshold != null) opts.threshold = options.threshold; + if (options.keyword_search != null) opts.keyword_search = options.keyword_search; + if (options.reranking != null) opts.reranking = options.reranking; + + const results = await this.client.search(query, opts); + return normalizeSearchResults(results); + } + + async get(memoryId: string): Promise { + await this.ensureClient(); + const result = await this.client.get(memoryId); + return normalizeMemoryItem(result); + } + + async getAll(options: ListOptions): Promise { + await this.ensureClient(); + const opts: Record = { user_id: options.user_id }; + if (options.run_id) opts.run_id = options.run_id; + if (options.page_size != null) opts.page_size = options.page_size; + + const results = await this.client.getAll(opts); + if (Array.isArray(results)) return results.map(normalizeMemoryItem); + // Some versions return { results: [...] } + if (results?.results && Array.isArray(results.results)) + return results.results.map(normalizeMemoryItem); + return []; + } + + async delete(memoryId: string): Promise { + await this.ensureClient(); + await this.client.delete(memoryId); + } +} + +// ============================================================================ +// Open-Source Provider (Self-hosted) +// ============================================================================ + +class OSSProvider implements Mem0Provider { + private memory: any; // Memory from mem0ai/oss + private initPromise: Promise | null = null; + + constructor( + private readonly ossConfig?: Mem0Config["oss"], + private readonly customPrompt?: string, + private readonly resolvePath?: (p: string) => string, + ) { } + + private async ensureMemory(): Promise { + if (this.memory) return; + if (this.initPromise) return this.initPromise; + this.initPromise = this._init(); + return this.initPromise; + } + + private async _init(): Promise { + const { Memory } = await import("mem0ai/oss"); + + const config: Record = { version: "v1.1" }; + + if (this.ossConfig?.embedder) config.embedder = this.ossConfig.embedder; + if (this.ossConfig?.vectorStore) + config.vectorStore = this.ossConfig.vectorStore; + if (this.ossConfig?.llm) config.llm = this.ossConfig.llm; + + if (this.ossConfig?.historyDbPath) { + const dbPath = this.resolvePath + ? this.resolvePath(this.ossConfig.historyDbPath) + : this.ossConfig.historyDbPath; + config.historyDbPath = dbPath; + } + + if (this.customPrompt) config.customPrompt = this.customPrompt; + + this.memory = new Memory(config); + } + + async add( + messages: Array<{ role: string; content: string }>, + options: AddOptions, + ): Promise { + await this.ensureMemory(); + // OSS SDK uses camelCase: userId/runId, not user_id/run_id + const addOpts: Record = { userId: options.user_id }; + if (options.run_id) addOpts.runId = options.run_id; + const result = await this.memory.add(messages, addOpts); + return normalizeAddResult(result); + } + + async search(query: string, options: SearchOptions): Promise { + await this.ensureMemory(); + // OSS SDK uses camelCase: userId/runId, not user_id/run_id + const opts: Record = { userId: options.user_id }; + if (options.run_id) opts.runId = options.run_id; + if (options.limit != null) opts.limit = options.limit; + else if (options.top_k != null) opts.limit = options.top_k; + if (options.keyword_search != null) opts.keyword_search = options.keyword_search; + if (options.reranking != null) opts.reranking = options.reranking; + + const results = await this.memory.search(query, opts); + return normalizeSearchResults(results); + } + + async get(memoryId: string): Promise { + await this.ensureMemory(); + const result = await this.memory.get(memoryId); + return normalizeMemoryItem(result); + } + + async getAll(options: ListOptions): Promise { + await this.ensureMemory(); + // OSS SDK uses camelCase: userId/runId, not user_id/run_id + const getAllOpts: Record = { userId: options.user_id }; + if (options.run_id) getAllOpts.runId = options.run_id; + const results = await this.memory.getAll(getAllOpts); + if (Array.isArray(results)) return results.map(normalizeMemoryItem); + if (results?.results && Array.isArray(results.results)) + return results.results.map(normalizeMemoryItem); + return []; + } + + async delete(memoryId: string): Promise { + await this.ensureMemory(); + await this.memory.delete(memoryId); + } +} + +// ============================================================================ +// Result Normalizers +// ============================================================================ + +function normalizeMemoryItem(raw: any): MemoryItem { + return { + id: raw.id ?? raw.memory_id ?? "", + memory: raw.memory ?? raw.text ?? raw.content ?? "", + // Handle both platform (user_id, created_at) and OSS (userId, createdAt) field names + user_id: raw.user_id ?? raw.userId, + score: raw.score, + categories: raw.categories, + metadata: raw.metadata, + created_at: raw.created_at ?? raw.createdAt, + updated_at: raw.updated_at ?? raw.updatedAt, + }; +} + +function normalizeSearchResults(raw: any): MemoryItem[] { + // Platform API returns flat array, OSS returns { results: [...] } + if (Array.isArray(raw)) return raw.map(normalizeMemoryItem); + if (raw?.results && Array.isArray(raw.results)) + return raw.results.map(normalizeMemoryItem); + return []; +} + +function normalizeAddResult(raw: any): AddResult { + // Handle { results: [...] } shape (both platform and OSS) + if (raw?.results && Array.isArray(raw.results)) { + return { + results: raw.results.map((r: any) => ({ + id: r.id ?? r.memory_id ?? "", + memory: r.memory ?? r.text ?? "", + // Platform API may return PENDING status (async processing) + // OSS stores event in metadata.event + event: r.event ?? r.metadata?.event ?? (r.status === "PENDING" ? "ADD" : "ADD"), + })), + }; + } + // Platform API without output_format returns flat array + if (Array.isArray(raw)) { + return { + results: raw.map((r: any) => ({ + id: r.id ?? r.memory_id ?? "", + memory: r.memory ?? r.text ?? "", + event: r.event ?? r.metadata?.event ?? (r.status === "PENDING" ? "ADD" : "ADD"), + })), + }; + } + return { results: [] }; +} + +// ============================================================================ +// Config Parser +// ============================================================================ + +function resolveEnvVars(value: string): string { + return value.replace(/\$\{([^}]+)\}/g, (_, envVar) => { + const envValue = process.env[envVar]; + if (!envValue) { + throw new Error(`Environment variable ${envVar} is not set`); + } + return envValue; + }); +} + +function resolveEnvVarsDeep(obj: Record): Record { + const result: Record = {}; + for (const [key, value] of Object.entries(obj)) { + if (typeof value === "string") { + result[key] = resolveEnvVars(value); + } else if (value && typeof value === "object" && !Array.isArray(value)) { + result[key] = resolveEnvVarsDeep(value as Record); + } else { + result[key] = value; + } + } + return result; +} + +// ============================================================================ +// Default Custom Instructions & Categories +// ============================================================================ + +const DEFAULT_CUSTOM_INSTRUCTIONS = `Your Task: Extract and maintain a structured, evolving profile of the user from their conversations with an AI assistant. Capture information that would help the assistant provide personalized, context-aware responses in future interactions. + +Information to Extract: + +1. Identity & Demographics: + - Name, age, location, timezone, language preferences + - Occupation, employer, job role, industry + - Education background + +2. Preferences & Opinions: + - Communication style preferences (formal/casual, verbose/concise) + - Tool and technology preferences (languages, frameworks, editors, OS) + - Content preferences (topics of interest, learning style) + - Strong opinions or values they've expressed + - Likes and dislikes they've explicitly stated + +3. Goals & Projects: + - Current projects they're working on (name, description, status) + - Short-term and long-term goals + - Deadlines and milestones mentioned + - Problems they're actively trying to solve + +4. Technical Context: + - Tech stack and tools they use + - Skill level in different areas (beginner/intermediate/expert) + - Development environment and setup details + - Recurring technical challenges + +5. Relationships & People: + - Names and roles of people they mention (colleagues, family, friends) + - Team structure and dynamics + - Key contacts and their relevance + +6. Decisions & Lessons: + - Important decisions made and their reasoning + - Lessons learned from past experiences + - Strategies that worked or failed + - Changed opinions or updated beliefs + +7. Routines & Habits: + - Daily routines and schedules mentioned + - Work patterns (when they're productive, how they organize work) + - Health and wellness habits if voluntarily shared + +8. Life Events: + - Significant events (new job, moving, milestones) + - Upcoming events or plans + - Changes in circumstances + +Guidelines: +- Store memories as clear, self-contained statements (each memory should make sense on its own) +- Use third person: "User prefers..." not "I prefer..." +- Include temporal context when relevant: "As of [date], user is working on..." +- When information updates, UPDATE the existing memory rather than creating duplicates +- Merge related facts into single coherent memories when possible +- Preserve specificity: "User uses Next.js 14 with App Router" is better than "User uses React" +- Capture the WHY behind preferences when stated: "User prefers Vim because of keyboard-driven workflow" + +Exclude: +- Passwords, API keys, tokens, or any authentication credentials +- Exact financial amounts (account balances, salaries) unless the user explicitly asks to remember them +- Temporary or ephemeral information (one-time questions, debugging sessions with no lasting insight) +- Generic small talk with no informational content +- The assistant's own responses unless they contain a commitment or promise to the user +- Raw code snippets (capture the intent/decision, not the code itself) +- Information the user explicitly asks not to remember`; + +const DEFAULT_CUSTOM_CATEGORIES: Record = { + identity: + "Personal identity information: name, age, location, timezone, occupation, employer, education, demographics", + preferences: + "Explicitly stated likes, dislikes, preferences, opinions, and values across any domain", + goals: + "Current and future goals, aspirations, objectives, targets the user is working toward", + projects: + "Specific projects, initiatives, or endeavors the user is working on, including status and details", + technical: + "Technical skills, tools, tech stack, development environment, programming languages, frameworks", + decisions: + "Important decisions made, reasoning behind choices, strategy changes, and their outcomes", + relationships: + "People mentioned by the user: colleagues, family, friends, their roles and relevance", + routines: + "Daily habits, work patterns, schedules, productivity routines, health and wellness habits", + life_events: + "Significant life events, milestones, transitions, upcoming plans and changes", + lessons: + "Lessons learned, insights gained, mistakes acknowledged, changed opinions or beliefs", + work: + "Work-related context: job responsibilities, workplace dynamics, career progression, professional challenges", + health: + "Health-related information voluntarily shared: conditions, medications, fitness, wellness goals", +}; + +// ============================================================================ +// Config Schema +// ============================================================================ + +const ALLOWED_KEYS = [ + "mode", + "apiKey", + "userId", + "orgId", + "projectId", + "autoCapture", + "autoRecall", + "customInstructions", + "customCategories", + "customPrompt", + "enableGraph", + "searchThreshold", + "topK", + "oss", +]; + +function assertAllowedKeys( + value: Record, + allowed: string[], + label: string, +) { + const unknown = Object.keys(value).filter((key) => !allowed.includes(key)); + if (unknown.length === 0) return; + throw new Error(`${label} has unknown keys: ${unknown.join(", ")}`); +} + +const mem0ConfigSchema = { + parse(value: unknown): Mem0Config { + if (!value || typeof value !== "object" || Array.isArray(value)) { + throw new Error("openclaw-mem0 config required"); + } + const cfg = value as Record; + assertAllowedKeys(cfg, ALLOWED_KEYS, "openclaw-mem0 config"); + + // Accept both "open-source" and legacy "oss" as open-source mode; everything else is platform + const mode: Mem0Mode = + cfg.mode === "oss" || cfg.mode === "open-source" ? "open-source" : "platform"; + + // Platform mode requires apiKey + if (mode === "platform") { + if (typeof cfg.apiKey !== "string" || !cfg.apiKey) { + throw new Error( + "apiKey is required for platform mode (set mode: \"open-source\" for self-hosted)", + ); + } + } + + // Resolve env vars in oss config + let ossConfig: Mem0Config["oss"]; + if (cfg.oss && typeof cfg.oss === "object" && !Array.isArray(cfg.oss)) { + ossConfig = resolveEnvVarsDeep( + cfg.oss as Record, + ) as unknown as Mem0Config["oss"]; + } + + return { + mode, + apiKey: + typeof cfg.apiKey === "string" ? resolveEnvVars(cfg.apiKey) : undefined, + userId: + typeof cfg.userId === "string" && cfg.userId ? cfg.userId : "default", + orgId: typeof cfg.orgId === "string" ? cfg.orgId : undefined, + projectId: typeof cfg.projectId === "string" ? cfg.projectId : undefined, + autoCapture: cfg.autoCapture !== false, + autoRecall: cfg.autoRecall !== false, + customInstructions: + typeof cfg.customInstructions === "string" + ? cfg.customInstructions + : DEFAULT_CUSTOM_INSTRUCTIONS, + customCategories: + cfg.customCategories && + typeof cfg.customCategories === "object" && + !Array.isArray(cfg.customCategories) + ? (cfg.customCategories as Record) + : DEFAULT_CUSTOM_CATEGORIES, + customPrompt: + typeof cfg.customPrompt === "string" + ? cfg.customPrompt + : DEFAULT_CUSTOM_INSTRUCTIONS, + enableGraph: cfg.enableGraph === true, + searchThreshold: + typeof cfg.searchThreshold === "number" ? cfg.searchThreshold : 0.5, + topK: typeof cfg.topK === "number" ? cfg.topK : 5, + oss: ossConfig, + }; + }, +}; + +// ============================================================================ +// Provider Factory +// ============================================================================ + +function createProvider( + cfg: Mem0Config, + api: OpenClawPluginApi, +): Mem0Provider { + if (cfg.mode === "open-source") { + return new OSSProvider(cfg.oss, cfg.customPrompt, (p) => + api.resolvePath(p), + ); + } + + return new PlatformProvider(cfg.apiKey!, cfg.orgId, cfg.projectId); +} + +// ============================================================================ +// Helpers +// ============================================================================ + +/** Convert Record categories to the array format mem0ai expects */ +function categoriesToArray( + cats: Record, +): Array> { + return Object.entries(cats).map(([key, value]) => ({ [key]: value })); +} + +// ============================================================================ +// Plugin Definition +// ============================================================================ + +const memoryPlugin = { + id: "openclaw-mem0", + name: "Memory (Mem0)", + description: + "Mem0 memory backend — Mem0 platform or self-hosted open-source", + kind: "memory" as const, + configSchema: mem0ConfigSchema, + + register(api: OpenClawPluginApi) { + const cfg = mem0ConfigSchema.parse(api.pluginConfig); + const provider = createProvider(cfg, api); + + // Track current session ID for tool-level session scoping + let currentSessionId: string | undefined; + + api.logger.info( + `openclaw-mem0: registered (mode: ${cfg.mode}, user: ${cfg.userId}, graph: ${cfg.enableGraph}, autoRecall: ${cfg.autoRecall}, autoCapture: ${cfg.autoCapture})`, + ); + + // Helper: build add options + function buildAddOptions(userIdOverride?: string, runId?: string): AddOptions { + const opts: AddOptions = { + user_id: userIdOverride || cfg.userId, + }; + if (runId) opts.run_id = runId; + if (cfg.mode === "platform") { + opts.custom_instructions = cfg.customInstructions; + opts.custom_categories = categoriesToArray(cfg.customCategories); + opts.enable_graph = cfg.enableGraph; + opts.output_format = "v1.1"; + } + return opts; + } + + // Helper: build search options + function buildSearchOptions( + userIdOverride?: string, + limit?: number, + runId?: string, + ): SearchOptions { + const opts: SearchOptions = { + user_id: userIdOverride || cfg.userId, + top_k: limit ?? cfg.topK, + limit: limit ?? cfg.topK, + threshold: cfg.searchThreshold, + keyword_search: true, + reranking: true, + }; + if (runId) opts.run_id = runId; + return opts; + } + + // ======================================================================== + // Tools + // ======================================================================== + + api.registerTool( + { + name: "memory_search", + label: "Memory Search", + description: + "Search through long-term memories stored in Mem0. Use when you need context about user preferences, past decisions, or previously discussed topics.", + parameters: Type.Object({ + query: Type.String({ description: "Search query" }), + limit: Type.Optional( + Type.Number({ + description: `Max results (default: ${cfg.topK})`, + }), + ), + userId: Type.Optional( + Type.String({ + description: + "User ID to scope search (default: configured userId)", + }), + ), + scope: Type.Optional( + Type.Union([ + Type.Literal("session"), + Type.Literal("long-term"), + Type.Literal("all"), + ], { + description: + 'Memory scope: "session" (current session only), "long-term" (user-scoped only), or "all" (both). Default: "all"', + }), + ), + }), + async execute(_toolCallId, params) { + const { query, limit, userId, scope = "all" } = params as { + query: string; + limit?: number; + userId?: string; + scope?: "session" | "long-term" | "all"; + }; + + try { + let results: MemoryItem[] = []; + + if (scope === "session") { + if (currentSessionId) { + results = await provider.search( + query, + buildSearchOptions(userId, limit, currentSessionId), + ); + } + } else if (scope === "long-term") { + results = await provider.search( + query, + buildSearchOptions(userId, limit), + ); + } else { + // "all" — search both scopes and combine + const longTermResults = await provider.search( + query, + buildSearchOptions(userId, limit), + ); + let sessionResults: MemoryItem[] = []; + if (currentSessionId) { + sessionResults = await provider.search( + query, + buildSearchOptions(userId, limit, currentSessionId), + ); + } + // Deduplicate by ID, preferring long-term + const seen = new Set(longTermResults.map((r) => r.id)); + results = [ + ...longTermResults, + ...sessionResults.filter((r) => !seen.has(r.id)), + ]; + } + + if (!results || results.length === 0) { + return { + content: [ + { type: "text", text: "No relevant memories found." }, + ], + details: { count: 0 }, + }; + } + + const text = results + .map( + (r, i) => + `${i + 1}. ${r.memory} (score: ${((r.score ?? 0) * 100).toFixed(0)}%, id: ${r.id})`, + ) + .join("\n"); + + const sanitized = results.map((r) => ({ + id: r.id, + memory: r.memory, + score: r.score, + categories: r.categories, + created_at: r.created_at, + })); + + return { + content: [ + { + type: "text", + text: `Found ${results.length} memories:\n\n${text}`, + }, + ], + details: { count: results.length, memories: sanitized }, + }; + } catch (err) { + return { + content: [ + { + type: "text", + text: `Memory search failed: ${String(err)}`, + }, + ], + details: { error: String(err) }, + }; + } + }, + }, + { name: "memory_search" }, + ); + + api.registerTool( + { + name: "memory_store", + label: "Memory Store", + description: + "Save important information in long-term memory via Mem0. Use for preferences, facts, decisions, and anything worth remembering.", + parameters: Type.Object({ + text: Type.String({ description: "Information to remember" }), + userId: Type.Optional( + Type.String({ + description: "User ID to scope this memory", + }), + ), + metadata: Type.Optional( + Type.Record(Type.String(), Type.Unknown(), { + description: "Optional metadata to attach to this memory", + }), + ), + longTerm: Type.Optional( + Type.Boolean({ + description: + "Store as long-term (user-scoped) memory. Default: true. Set to false for session-scoped memory.", + }), + ), + }), + async execute(_toolCallId, params) { + const { text, userId, longTerm = true } = params as { + text: string; + userId?: string; + metadata?: Record; + longTerm?: boolean; + }; + + try { + const runId = !longTerm && currentSessionId ? currentSessionId : undefined; + const result = await provider.add( + [{ role: "user", content: text }], + buildAddOptions(userId, runId), + ); + + const added = + result.results?.filter((r) => r.event === "ADD") ?? []; + const updated = + result.results?.filter((r) => r.event === "UPDATE") ?? []; + + const summary = []; + if (added.length > 0) + summary.push( + `${added.length} new memor${added.length === 1 ? "y" : "ies"} added`, + ); + if (updated.length > 0) + summary.push( + `${updated.length} memor${updated.length === 1 ? "y" : "ies"} updated`, + ); + if (summary.length === 0) + summary.push("No new memories extracted"); + + return { + content: [ + { + type: "text", + text: `Stored: ${summary.join(", ")}. ${result.results?.map((r) => `[${r.event}] ${r.memory}`).join("; ") ?? ""}`, + }, + ], + details: { + action: "stored", + results: result.results, + }, + }; + } catch (err) { + return { + content: [ + { + type: "text", + text: `Memory store failed: ${String(err)}`, + }, + ], + details: { error: String(err) }, + }; + } + }, + }, + { name: "memory_store" }, + ); + + api.registerTool( + { + name: "memory_get", + label: "Memory Get", + description: "Retrieve a specific memory by its ID from Mem0.", + parameters: Type.Object({ + memoryId: Type.String({ description: "The memory ID to retrieve" }), + }), + async execute(_toolCallId, params) { + const { memoryId } = params as { memoryId: string }; + + try { + const memory = await provider.get(memoryId); + + return { + content: [ + { + type: "text", + text: `Memory ${memory.id}:\n${memory.memory}\n\nCreated: ${memory.created_at ?? "unknown"}\nUpdated: ${memory.updated_at ?? "unknown"}`, + }, + ], + details: { memory }, + }; + } catch (err) { + return { + content: [ + { + type: "text", + text: `Memory get failed: ${String(err)}`, + }, + ], + details: { error: String(err) }, + }; + } + }, + }, + { name: "memory_get" }, + ); + + api.registerTool( + { + name: "memory_list", + label: "Memory List", + description: + "List all stored memories for a user. Use this when you want to see everything that's been remembered, rather than searching for something specific.", + parameters: Type.Object({ + userId: Type.Optional( + Type.String({ + description: + "User ID to list memories for (default: configured userId)", + }), + ), + scope: Type.Optional( + Type.Union([ + Type.Literal("session"), + Type.Literal("long-term"), + Type.Literal("all"), + ], { + description: + 'Memory scope: "session" (current session only), "long-term" (user-scoped only), or "all" (both). Default: "all"', + }), + ), + }), + async execute(_toolCallId, params) { + const { userId, scope = "all" } = params as { userId?: string; scope?: "session" | "long-term" | "all" }; + + try { + let memories: MemoryItem[] = []; + const uid = userId || cfg.userId; + + if (scope === "session") { + if (currentSessionId) { + memories = await provider.getAll({ + user_id: uid, + run_id: currentSessionId, + }); + } + } else if (scope === "long-term") { + memories = await provider.getAll({ user_id: uid }); + } else { + // "all" — combine both scopes + const longTerm = await provider.getAll({ user_id: uid }); + let session: MemoryItem[] = []; + if (currentSessionId) { + session = await provider.getAll({ + user_id: uid, + run_id: currentSessionId, + }); + } + const seen = new Set(longTerm.map((r) => r.id)); + memories = [ + ...longTerm, + ...session.filter((r) => !seen.has(r.id)), + ]; + } + + if (!memories || memories.length === 0) { + return { + content: [ + { type: "text", text: "No memories stored yet." }, + ], + details: { count: 0 }, + }; + } + + const text = memories + .map( + (r, i) => + `${i + 1}. ${r.memory} (id: ${r.id})`, + ) + .join("\n"); + + const sanitized = memories.map((r) => ({ + id: r.id, + memory: r.memory, + categories: r.categories, + created_at: r.created_at, + })); + + return { + content: [ + { + type: "text", + text: `${memories.length} memories:\n\n${text}`, + }, + ], + details: { count: memories.length, memories: sanitized }, + }; + } catch (err) { + return { + content: [ + { + type: "text", + text: `Memory list failed: ${String(err)}`, + }, + ], + details: { error: String(err) }, + }; + } + }, + }, + { name: "memory_list" }, + ); + + api.registerTool( + { + name: "memory_forget", + label: "Memory Forget", + description: + "Delete memories from Mem0. Provide a specific memoryId to delete directly, or a query to search and delete matching memories. GDPR-compliant.", + parameters: Type.Object({ + query: Type.Optional( + Type.String({ + description: "Search query to find memory to delete", + }), + ), + memoryId: Type.Optional( + Type.String({ description: "Specific memory ID to delete" }), + ), + }), + async execute(_toolCallId, params) { + const { query, memoryId } = params as { + query?: string; + memoryId?: string; + }; + + try { + if (memoryId) { + await provider.delete(memoryId); + return { + content: [ + { type: "text", text: `Memory ${memoryId} forgotten.` }, + ], + details: { action: "deleted", id: memoryId }, + }; + } + + if (query) { + const results = await provider.search( + query, + buildSearchOptions(undefined, 5), + ); + + if (!results || results.length === 0) { + return { + content: [ + { type: "text", text: "No matching memories found." }, + ], + details: { found: 0 }, + }; + } + + // If single high-confidence match, delete directly + if ( + results.length === 1 || + (results[0].score ?? 0) > 0.9 + ) { + await provider.delete(results[0].id); + return { + content: [ + { + type: "text", + text: `Forgotten: "${results[0].memory}"`, + }, + ], + details: { action: "deleted", id: results[0].id }, + }; + } + + const list = results + .map( + (r) => + `- [${r.id}] ${r.memory.slice(0, 80)}${r.memory.length > 80 ? "..." : ""} (score: ${((r.score ?? 0) * 100).toFixed(0)}%)`, + ) + .join("\n"); + + const candidates = results.map((r) => ({ + id: r.id, + memory: r.memory, + score: r.score, + })); + + return { + content: [ + { + type: "text", + text: `Found ${results.length} candidates. Specify memoryId to delete:\n${list}`, + }, + ], + details: { action: "candidates", candidates }, + }; + } + + return { + content: [ + { type: "text", text: "Provide a query or memoryId." }, + ], + details: { error: "missing_param" }, + }; + } catch (err) { + return { + content: [ + { + type: "text", + text: `Memory forget failed: ${String(err)}`, + }, + ], + details: { error: String(err) }, + }; + } + }, + }, + { name: "memory_forget" }, + ); + + // ======================================================================== + // CLI Commands + // ======================================================================== + + api.registerCli( + ({ program }) => { + const mem0 = program + .command("mem0") + .description("Mem0 memory plugin commands"); + + mem0 + .command("search") + .description("Search memories in Mem0") + .argument("", "Search query") + .option("--limit ", "Max results", String(cfg.topK)) + .option("--scope ", 'Memory scope: "session", "long-term", or "all"', "all") + .action(async (query: string, opts: { limit: string; scope: string }) => { + try { + const limit = parseInt(opts.limit, 10); + const scope = opts.scope as "session" | "long-term" | "all"; + + let allResults: MemoryItem[] = []; + + if (scope === "session" || scope === "all") { + if (currentSessionId) { + const sessionResults = await provider.search( + query, + buildSearchOptions(undefined, limit, currentSessionId), + ); + if (sessionResults?.length) { + allResults.push(...sessionResults.map((r) => ({ ...r, _scope: "session" as const }))); + } + } else if (scope === "session") { + console.log("No active session ID available for session-scoped search."); + return; + } + } + + if (scope === "long-term" || scope === "all") { + const longTermResults = await provider.search( + query, + buildSearchOptions(undefined, limit), + ); + if (longTermResults?.length) { + allResults.push(...longTermResults.map((r) => ({ ...r, _scope: "long-term" as const }))); + } + } + + // Deduplicate by ID when searching "all" + if (scope === "all") { + const seen = new Set(); + allResults = allResults.filter((r) => { + if (seen.has(r.id)) return false; + seen.add(r.id); + return true; + }); + } + + if (!allResults.length) { + console.log("No memories found."); + return; + } + + const output = allResults.map((r) => ({ + id: r.id, + memory: r.memory, + score: r.score, + scope: (r as any)._scope, + categories: r.categories, + created_at: r.created_at, + })); + console.log(JSON.stringify(output, null, 2)); + } catch (err) { + console.error(`Search failed: ${String(err)}`); + } + }); + + mem0 + .command("stats") + .description("Show memory statistics from Mem0") + .action(async () => { + try { + const memories = await provider.getAll({ + user_id: cfg.userId, + }); + console.log(`Mode: ${cfg.mode}`); + console.log(`User: ${cfg.userId}`); + console.log( + `Total memories: ${Array.isArray(memories) ? memories.length : "unknown"}`, + ); + console.log(`Graph enabled: ${cfg.enableGraph}`); + console.log( + `Auto-recall: ${cfg.autoRecall}, Auto-capture: ${cfg.autoCapture}`, + ); + } catch (err) { + console.error(`Stats failed: ${String(err)}`); + } + }); + }, + { commands: ["mem0"] }, + ); + + // ======================================================================== + // Lifecycle Hooks + // ======================================================================== + + // Auto-recall: inject relevant memories before agent starts + if (cfg.autoRecall) { + api.on("before_agent_start", async (event, ctx) => { + if (!event.prompt || event.prompt.length < 5) return; + + // Track session ID + const sessionId = (ctx as any)?.sessionKey ?? undefined; + if (sessionId) currentSessionId = sessionId; + + try { + // Search long-term memories (user-scoped) + const longTermResults = await provider.search( + event.prompt, + buildSearchOptions(), + ); + + // Search session memories (session-scoped) if we have a session ID + let sessionResults: MemoryItem[] = []; + if (currentSessionId) { + sessionResults = await provider.search( + event.prompt, + buildSearchOptions(undefined, undefined, currentSessionId), + ); + } + + // Deduplicate session results against long-term + const longTermIds = new Set(longTermResults.map((r) => r.id)); + const uniqueSessionResults = sessionResults.filter( + (r) => !longTermIds.has(r.id), + ); + + if (longTermResults.length === 0 && uniqueSessionResults.length === 0) return; + + // Build context with clear labels + let memoryContext = ""; + if (longTermResults.length > 0) { + memoryContext += longTermResults + .map( + (r) => + `- ${r.memory}${r.categories?.length ? ` [${r.categories.join(", ")}]` : ""}`, + ) + .join("\n"); + } + if (uniqueSessionResults.length > 0) { + if (memoryContext) memoryContext += "\n"; + memoryContext += "\nSession memories:\n"; + memoryContext += uniqueSessionResults + .map((r) => `- ${r.memory}`) + .join("\n"); + } + + const totalCount = longTermResults.length + uniqueSessionResults.length; + api.logger.info( + `openclaw-mem0: injecting ${totalCount} memories into context (${longTermResults.length} long-term, ${uniqueSessionResults.length} session)`, + ); + + return { + systemContext: `\nThe following memories may be relevant to this conversation:\n${memoryContext}\n`, + }; + } catch (err) { + api.logger.warn(`openclaw-mem0: recall failed: ${String(err)}`); + } + }); + } + + // Auto-capture: store conversation context after agent ends + if (cfg.autoCapture) { + api.on("agent_end", async (event, ctx) => { + if (!event.success || !event.messages || event.messages.length === 0) { + return; + } + + // Track session ID + const sessionId = (ctx as any)?.sessionKey ?? undefined; + if (sessionId) currentSessionId = sessionId; + + try { + // Extract messages, limiting to last 10 + const recentMessages = event.messages.slice(-10); + const formattedMessages: Array<{ + role: string; + content: string; + }> = []; + + for (const msg of recentMessages) { + if (!msg || typeof msg !== "object") continue; + const msgObj = msg as Record; + + const role = msgObj.role; + if (role !== "user" && role !== "assistant") continue; + + let textContent = ""; + const content = msgObj.content; + + if (typeof content === "string") { + textContent = content; + } else if (Array.isArray(content)) { + for (const block of content) { + if ( + block && + typeof block === "object" && + "type" in block && + (block as Record).type === "text" && + "text" in block && + typeof (block as Record).text === "string" + ) { + textContent += + (textContent ? "\n" : "") + + ((block as Record).text as string); + } + } + } + + if (!textContent) continue; + // Skip injected memory context + if (textContent.includes("")) continue; + + formattedMessages.push({ + role: role as string, + content: textContent, + }); + } + + if (formattedMessages.length === 0) return; + + const addOpts = buildAddOptions(undefined, currentSessionId); + const result = await provider.add( + formattedMessages, + addOpts, + ); + + const capturedCount = result.results?.length ?? 0; + if (capturedCount > 0) { + api.logger.info( + `openclaw-mem0: auto-captured ${capturedCount} memories`, + ); + } + } catch (err) { + api.logger.warn(`openclaw-mem0: capture failed: ${String(err)}`); + } + }); + } + + // ======================================================================== + // Service + // ======================================================================== + + api.registerService({ + id: "openclaw-mem0", + start: () => { + api.logger.info( + `openclaw-mem0: initialized (mode: ${cfg.mode}, user: ${cfg.userId}, autoRecall: ${cfg.autoRecall}, autoCapture: ${cfg.autoCapture})`, + ); + }, + stop: () => { + api.logger.info("openclaw-mem0: stopped"); + }, + }); + }, +}; + +export default memoryPlugin; diff --git a/openclaw/openclaw.plugin.json b/openclaw/openclaw.plugin.json new file mode 100644 index 000000000..75392b790 --- /dev/null +++ b/openclaw/openclaw.plugin.json @@ -0,0 +1,168 @@ +{ + "id": "openclaw-mem0", + "kind": "memory", + "uiHints": { + "mode": { + "label": "Mode", + "help": "\"platform\" for Mem0 cloud, \"open-source\" for self-hosted" + }, + "apiKey": { + "label": "Mem0 API Key", + "sensitive": true, + "placeholder": "m0-...", + "help": "API key from app.mem0.ai (or use ${MEM0_API_KEY}). Only needed for platform mode." + }, + "userId": { + "label": "Default User ID", + "placeholder": "default", + "help": "User ID for scoping memories" + }, + "orgId": { + "label": "Organization ID", + "placeholder": "org-...", + "advanced": true + }, + "projectId": { + "label": "Project ID", + "placeholder": "proj-...", + "advanced": true + }, + "autoCapture": { + "label": "Auto-Capture", + "help": "Automatically store conversation context after each agent turn" + }, + "autoRecall": { + "label": "Auto-Recall", + "help": "Automatically inject relevant memories before each agent turn" + }, + "customInstructions": { + "label": "Custom Instructions", + "placeholder": "Only store user preferences and important facts...", + "help": "Natural language rules for what Mem0 should store or exclude (platform mode)" + }, + "customCategories": { + "label": "Custom Categories", + "advanced": true, + "help": "Map of category names to descriptions for memory tagging (platform mode only). Sensible defaults are built in." + }, + "customPrompt": { + "label": "Custom Prompt (Open-Source)", + "advanced": true, + "help": "Custom prompt for open-source mode memory extraction." + }, + "enableGraph": { + "label": "Enable Graph Memory", + "help": "Enable Mem0 graph memory for entity relationships (platform mode only)" + }, + "searchThreshold": { + "label": "Search Threshold", + "placeholder": "0.5", + "help": "Minimum similarity score for search results (0-1). Default: 0.5" + }, + "topK": { + "label": "Top K Results", + "placeholder": "5", + "help": "Maximum number of memories to retrieve" + }, + "oss": { + "label": "Open-Source Configuration", + "advanced": true, + "help": "Optional. Configure custom embedder, vector store, LLM, or history DB for open-source mode. Has sensible defaults — only override what you need." + } + }, + "configSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "mode": { + "type": "string", + "enum": [ + "platform", + "open-source", + "oss" + ] + }, + "apiKey": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "orgId": { + "type": "string" + }, + "projectId": { + "type": "string" + }, + "autoCapture": { + "type": "boolean" + }, + "autoRecall": { + "type": "boolean" + }, + "customInstructions": { + "type": "string" + }, + "customCategories": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "customPrompt": { + "type": "string" + }, + "enableGraph": { + "type": "boolean" + }, + "searchThreshold": { + "type": "number" + }, + "topK": { + "type": "number" + }, + "oss": { + "type": "object", + "properties": { + "embedder": { + "type": "object", + "properties": { + "provider": { + "type": "string" + }, + "config": { + "type": "object" + } + } + }, + "vectorStore": { + "type": "object", + "properties": { + "provider": { + "type": "string" + }, + "config": { + "type": "object" + } + } + }, + "llm": { + "type": "object", + "properties": { + "provider": { + "type": "string" + }, + "config": { + "type": "object" + } + } + }, + "historyDbPath": { + "type": "string" + } + } + } + }, + "required": [] + } +} \ No newline at end of file diff --git a/openclaw/package.json b/openclaw/package.json new file mode 100644 index 000000000..e2bdb87cc --- /dev/null +++ b/openclaw/package.json @@ -0,0 +1,23 @@ +{ + "name": "@mem0/openclaw-mem0", + "version": "0.1.0", + "type": "module", + "description": "Mem0 memory backend for OpenClaw — platform or self-hosted open-source", + "license": "Apache-2.0", + "keywords": [ + "openclaw", + "plugin", + "memory", + "mem0", + "long-term-memory" + ], + "dependencies": { + "@sinclair/typebox": "0.34.47", + "mem0ai": "^2.2.1" + }, + "openclaw": { + "extensions": [ + "./index.ts" + ] + } +} \ No newline at end of file